mskql vs PostgreSQL

Two benchmarks, one honest picture

← back to main page


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.

⚠ Important caveat. This comparison is unscientific and intended only as a directional indicator. mskql is an in-memory toy database with no durability, no MVCC, no WAL, no background workers, and no query optimizer. PostgreSQL is a production-grade RDBMS with decades of engineering behind it. The numbers below measure wall-clock time for identical SQL workloads over a loopback TCP connection—not raw engine speed. Take them as a rough sense of where mskql sits, not as a serious benchmark.

1. Methodology

Batch latency

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.

Concurrent throughput

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).

2. Batch Latency (single client, sequential)

Ratio < 1.0 means mskql was faster; > 1.0 means PostgreSQL was faster. Results vary between runs—treat these as order-of-magnitude indicators.

mskql PostgreSQL
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×).

3. Concurrent Throughput (4 threads, 5 seconds)

Ratio > 1.0 means mskql has higher throughput.

mskql PostgreSQL
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

4. The Honest Picture

Where mskql wins

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.

Where PostgreSQL is close

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.

5. What’s Next

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.

6. Running It Yourself

Batch latency

# Start mskql in one terminal
./build/mskql

# In another terminal, with PostgreSQL running:
./bench/bench_vs_pg.sh

Concurrent throughput

# 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.