mskql is faster than PostgreSQL in all 19 batch workloads. Aggregates run 9× faster. Inserts 3×. Under concurrent load, mskql wins 5 of 7 workloads—aggregate throughput is 9.4× higher. PostgreSQL wins on full table scans and filtered scans where the network dominates.
Both databases are tested on the same Apple M-series laptop, same loopback interface,
using the same psql client. The benchmark script
(bench/bench_vs_pg.py) generates identical SQL workloads for each test,
runs setup against both databases, then times the benchmark queries. Each timing measures
a single psql -f invocation containing all iterations of that workload.
mskql runs on port 5433; PostgreSQL on port 5432 with default configuration.
A multi-threaded C benchmark (bench/bench_throughput.c) opens 4 persistent
libpq connections and fires queries for 5 seconds per workload.
Measures QPS and median latency (p50).
Ratio < 1.0 means mskql was faster; > 1.0 means PostgreSQL was faster. Results vary between runs—treat these as order-of-magnitude indicators.
| Workload | mskql (ms) | pg (ms) | Ratio | |
|---|---|---|---|---|
| reads | ||||
| select_full_scan | 294 | 451 | 0.65× | |
| select_where | 352 | 610 | 0.58× | |
| index_lookup | 103 | 107 | 0.96× | |
| order_by | 194 | 372 | 0.52× | |
| multi_sort | 271 | 506 | 0.54× | |
| distinct | 37 | 257 | 0.14× | |
| writes | ||||
| insert_bulk | 325 | 872 | 0.37× | |
| update | 46 | 231 | 0.20× | |
| delete | 2,964 | 7,976 | 0.37× | |
| transaction | 180 | 191 | 0.94× | |
| advanced queries | ||||
| aggregate | 31 | 274 | 0.11× | |
| join | 26 | 58 | 0.45× | |
| window_functions | 50 | 88 | 0.56× | |
| subquery | 40 | 93 | 0.43× | |
| cte | 50 | 113 | 0.44× | |
| set_ops | 52 | 98 | 0.53× | |
| generate_series | 212 | 710 | 0.30× | |
| scalar_functions | 358 | 944 | 0.38× | |
| expression_agg | 304 | 313 | 0.97× | |
All 19 workloads faster. The closest results are expression aggregates (0.97×), transactions (0.94×), and index lookups (0.96×).
Ratio > 1.0 means mskql has higher throughput.
| Workload | mskql QPS | pg QPS | Ratio | mskql p50 | pg p50 | |
|---|---|---|---|---|---|---|
| point_read | 51,786 | 46,882 | 1.10× | 0.074 ms | 0.085 ms | |
| full_scan | 240 | 270 | 0.89× | 14.9 ms | 13.7 ms | |
| filtered_scan | 484 | 548 | 0.88× | 6.7 ms | 6.7 ms | |
| aggregate | 52,319 | 5,539 | 9.44× | 0.073 ms | 0.727 ms | |
| join | 1,311 | 651 | 2.01× | 2.8 ms | 5.4 ms | |
| insert | 57,217 | 27,840 | 2.06× | 0.067 ms | 0.135 ms | |
| mixed_rw | 45,473 | 42,892 | 1.06× | 0.083 ms | 0.085 ms |
Aggregate: 0.11× (9× faster). Distinct: 0.14× (7× faster). Both driven by the block-oriented plan executor—1,024-row column blocks serialized directly to the wire without row materialization.
Write workloads benefit from zero durability overhead: no fsync, no WAL. Updates at 0.20× and inserts at 0.37× reflect the in-memory advantage. Transactions now run at 0.94× thanks to lazy copy-on-write snapshots.
Under concurrent load, aggregate throughput is 9.4× PostgreSQL’s (52,319 vs 5,539 QPS). Insert throughput is 2.06×. Join throughput is 2.01×. Point reads and mixed R/W also favor mskql.
Full scans and filtered scans: 0.89× / 0.88× throughput. Both databases are network-bound under concurrent load—serializing thousands of rows over the wire. The scan itself is fast in both. In batch mode mskql still wins (0.65× / 0.58×).
Expression aggregates: 0.97×. Complex expressions in aggregates are evaluated per-row in both engines. The gap is narrow.
The remaining throughput gaps (full_scan, filtered_scan) are network-bound. The batch results show mskql faster across all 19 workloads. The query engine is competitive or faster across the board.
# Start mskql in one terminal
./build/mskql
# In another terminal, with PostgreSQL running:
./bench/bench_vs_pg.sh
# Build the throughput benchmark
make -C bench bench_throughput
# Run (requires both mskql and PostgreSQL running)
./build/mskql_bench_tp --duration 5 --threads 4 --pg
The batch script auto-creates a mskql_bench database in PostgreSQL if it
doesn’t exist. The throughput benchmark requires libpq headers
at build time.