Timings on the Four-CPU Host

The host is shared: other lanes' Java jobs kept the load average between 3.4 and 8.9 on four CPUs, so absolute times swing between runs. One run, seven repetitions per query:

Running the benchmark
RUNS=7 bash scripts/bench.sh
Output
load: 7.74 5.33 3.93; containers: l2-pg
query scale      pg_ms    duck_ms  pg/duck
Q1   1x         94.63       3.38     28.0
Q2   1x        137.91      14.03      9.8
Q3   1x        316.86      93.39      3.4
Q4   1x        127.43      30.79      4.1
Q5   1x          0.20       2.19      0.1
Q6   1x          2.09       1.01      2.1
Q1   10x       747.07      38.83     19.2
Q2   10x      1178.14     126.83      9.3
Q3   10x      3219.53     233.20     13.8
Q4   10x       586.33      64.03      9.2
Q5   10x         0.10       1.82      0.1
Q6   10x         2.02       1.57      1.3
load: 8.93 6.58 4.53

Across four runs the pg/duck ratios ranged, at 1x and 10x: Q1 18-35 and 10-32, Q2 1.4-9.8 and 8.3-15, Q3 2.9-8.4 and 14-20, Q4 3.5-6.1 and 6.1-10. DuckDB 61,228 won every analytical query, by an order of magnitude on the plain scan, and its lead on the join, distinct count and window queries widened with the data. PostgreSQL 1,289 won the point lookup by 10 to 180 times (0.1 to 0.2 ms against about 2 ms); the single-row update took 1 to 2 ms on both.