mskql

An in-memory analytics database. Faster than PostgreSQL on every analytical workload. Beats DuckDB on aggregates, joins, CTEs, writes, and stress tests. Connects with psql.

Martin S. Kristiansen  ·  github.com/martinsk/mskql  ·  Tutorials


An in-memory SQL database that speaks the PostgreSQL wire protocol. Analytical queries return in single-digit milliseconds. Run the same query twice and the answer comes back in microseconds. Connect with psql, pgAdmin, DBeaver, or any PostgreSQL driver on port 5433. Query Parquet files with standard SQL. Store vector embeddings alongside your data. The entire engine compiles to WebAssembly—try it in the browser with zero infrastructure.

The performance comes from removing layers, not adding them. No buffer pool, no WAL, no MVCC, no query planner—just four stages from TCP bytes to results. Details in Architecture and Design philosophy.

Performance: mskql vs PostgreSQL vs DuckDB

Tested against PostgreSQL and DuckDB on batch latency, concurrent throughput, and Parquet workloads. Aggregates finish 20× faster than PostgreSQL. Correlated subqueries that take PostgreSQL 3.5 seconds complete in 6 milliseconds. A dashboard polling analytical queries sustains 97,000 queries per second—191× PostgreSQL. DuckDB wins full scans (2.9×) and sorts (1.2–2.0×). Disk-backed tables add persistence at 0.96× the in-memory speed.

Batch latency — shorter bars = faster

mskql PostgreSQL DuckDB
Correlated subquery
mskql
6ms
PG
3,456ms
Duck
45ms
Expression aggregate
mskql
14ms
PG
302ms
Duck
221ms
Group + sum
mskql
15ms
PG
280ms
Duck
245ms
Single-row inserts
mskql
264ms
PG
1,505ms
Duck
2,098ms
Analytical CTE
mskql
5ms
PG
66ms
Duck
32ms
Parquet aggregate
mskql
12ms
Duck
104ms
Full table scan
mskql
189ms
PG
213ms
Duck
65ms
Large sort
mskql
135ms
PG
212ms
Duck
50ms

Concurrent throughput — queries per second, 8 threads (longer = faster)

Think of each bar as a dashboard panel polling the same query. At 97K QPS, every panel refreshes in under a millisecond.

mskql PostgreSQL
Mixed analytical
mskql
97,210 QPS
PG
508 QPS
Multi-join
mskql
37,402 QPS
PG
475 QPS
Group + sum
mskql
97,210 QPS
PG
14,305 QPS
Indexed point lookup
mskql
86,805 QPS
PG
24,048 QPS

→ All batch + throughput + Parquet results  ·  Historical charts

Drop-in PostgreSQL compatibility

Every tool that talks to PostgreSQL already talks to mskql. Connect with psql, pgAdmin, DBeaver, or any language driver—Python, Go, Node, Java, Rust. Prepared statements and COPY work out of the box. Default port 5433.

make && ./build/mskql                         # build & start
psql -h 127.0.0.1 -p 5433 -U test -d mskql   # connect

Query Parquet files with standard SQL

CREATE FOREIGN TABLE maps a Parquet file to a SQL table. No ETL, no data loading—query directly with joins, aggregates, and subqueries. Run the same query twice and it returns instantly—the engine remembers the answer.

CREATE FOREIGN TABLE events
    OPTIONS (filename '/data/events.parquet');

SELECT event_type, COUNT(*), SUM(amount)
FROM events
GROUP BY event_type;

12 Parquet workloads (50K–200K rows). Aggregates 8.7× faster than DuckDB. Subqueries 11× faster. Joins 7ms vs 37ms. mskql wins 8 of 12 cached. DuckDB wins full scans, sorts, WHERE scans, and pq_mixed_join.

→ All 12 Parquet benchmark results

Native vector columns

Store embeddings alongside your relational data. VECTOR(n) is a first-class column type with pgvector-compatible syntax—no separate vector database needed. Insert, scan, filter, and sort vector columns through the same SQL you already know.

CREATE TABLE items (
    id    INT PRIMARY KEY,
    name  TEXT,
    embed VECTOR(3)
);

INSERT INTO items VALUES
    (1, 'cat',    '[0.1, 0.9, 0.3]'),
    (2, 'dog',    '[0.2, 0.8, 0.4]'),
    (3, 'fish',   '[0.9, 0.1, 0.7]'),
    (4, 'parrot', '[0.3, 0.7, 0.5]');

SELECT name, embed FROM items WHERE id > 1 ORDER BY name;

7 vector benchmarks against PostgreSQL + pgvector on the same machine. Wins all 7: insert 2.8×, scan 1.8×, wide scan 2.5×, filter 3.2× faster. Faster on every workload even when results aren’t cached.

→ All 7 vector benchmark results

Correctness guarantee

Every query produces bit-identical output to PostgreSQL. 1,514 adversarial test cases verify this, and every one runs under AddressSanitizer to catch memory errors. Three agents work in adversarial rounds: one writes tests designed to break the system, one reviews code, one fixes. The result is a database you can trust with the same SQL you run on PostgreSQL.

→ Read more about the process

Challenger adversarial tests Writer writes & fixes Reviewer code review iterate until all 1,514 tests pass

Try it — right here

A fully functional mskql database running entirely in your browser via WebAssembly—no server, no network requests. Choose an example or write your own SQL.

Loading WebAssembly…
Run a query to see results here.

→ Open full playground  (more space, more examples)

Build & connect

Ten queries from CREATE TABLE to recursive CTEs, all through psql.

Getting started →

Read the source

~57,140 lines of C11. Every subsystem in a single file.

GitHub →

Reference

Architecture — wire protocol, parser, vectorized executor, storage. One .c file per subsystem.
Design philosophy — why minimal abstraction leads to faster, more debuggable systems.
SQL reference — DDL, DML, joins, aggregation, window functions, CTEs, subqueries, 30+ built-in functions.  Grammar
Testing — 1,514 test cases, every one under a memory-safety checker. Parallel execution across all cores.
Benchmarks — mskql vs PostgreSQL and DuckDB on 101 batch workloads and 15 throughput workloads.  Historical charts