bench3.sh reruns DuckDB Extensions vs Postgres's six queries on the 1,379,440-row tables in all three engines: PostgreSQL 18.6 1,289 (psql \timing), DuckDB 1.5.5 61,228 (Python client) and ClickHouse 26.9 29,491 (clickhouse client --time, millisecond resolution). The SQL is identical except Q6, a mutation (ALTER TABLE ... UPDATE) in ClickHouse. Other lanes' jobs kept the load average at 3.4 to 8.4 on the four CPUs; this is one of three runs:
RUNS=5 bash scripts/bench3.shload: 3.38 4.85 4.79; containers: l2-clickhouse l2-pg query pg_ms duck_ms ch_ms Q1 469.88 16.46 50.00 Q2 684.86 48.86 129.00 Q3 2863.88 255.33 63.00 Q4 836.01 124.22 112.00 Q5 0.18 1.68 6.00 Q6 2.54 1.37 227.00
Over the three runs ClickHouse beat PostgreSQL 4.8-9.4x on Q1, 3.7-5.9x on Q2, 38-45x on Q3 and 4.0-7.5x on Q4. DuckDB, in-process with no client round trip, was 2.8-3.3x faster than ClickHouse on Q1 and 1.8-2.9x on Q2, about even on Q4, while ClickHouse's exact distinct count (Q3) beat DuckDB's 2.8-4.2x. ClickHouse lost the point lookup (5 to 14 ms), since order_id ends its key, and the update (0.2 to 0.5 s), since a mutation rewrites column files. A single-user benchmark also hides its strength, many concurrent queries over continuously arriving data. Use PostgreSQL for transactions, DuckDB inside a process or pipeline, and ClickHouse for a growing event table many users query.