32 microseconds at any offset depth. Up to 334× faster than PostgreSQL 13 for deep pagination. Every CRM, ERP, admin dashboard, and list endpoint runs on this path — and it’s the first thing to break under load.
Almost every line-of-business application paginates:
SELECT … FROM leads ORDER BY created_at LIMIT 25 OFFSET 500SELECT … FROM invoices LEFT JOIN customers … LIMIT 50 OFFSET 10000SELECT … FROM audit_log ORDER BY ts DESC LIMIT 100 OFFSET 50000On most databases, the cost of OFFSET grows linearly with depth. At 1k rows it’s fine; at 100k it’s a support ticket. HeliosDB Nano 3.12 pushes the OFFSET skip into the storage engine and does it without deserialising skipped rows — so the 10 000th page costs the same as the 1st.
Same hardware, same connection protocol (psycopg over Unix socket), same table, same queries. 100 000 rows, 20 samples per shape plus 3 warm-up, median reported.
ORDER BY id LIMIT 10 OFFSET M| Offset depth | HeliosDB Nano 3.12 | PostgreSQL 13 | Speedup |
|---|---|---|---|
| 0 | 32 µs | 49 µs | 1.5× |
| 100 | 37 µs | 57 µs | 1.5× |
| 1 000 | 32 µs | 144 µs | 4.5× |
| 10 000 | 36 µs | 1 194 µs | 33× |
| 99 990 | 32 µs | 10 688 µs | 334× |
Nano is flat — depth 99 990 costs the same as depth 0. PostgreSQL scales linearly with offset because every skipped tuple still goes through visibility checks and deserialisation.
WHERE id > $last ORDER BY id LIMIT 10This is the canonical “do-it-right” pagination shape. Nano and PostgreSQL both handle it with index seeks, so the numbers are close.
| Cursor position | HeliosDB Nano 3.12 | PostgreSQL 13 |
|---|---|---|
| first page | 31 µs | 84 µs |
| after id=10 001 | 32 µs | 50 µs |
| after id=99 990 | 33 µs | 69 µs |
LEFT OUTER JOIN + LIMIT + OFFSETThe shape SQLAlchemy emits for select(Lead, Company.name).outerjoin(Company).limit(N).offset(M):
| Offset depth | HeliosDB Nano 3.12 | PostgreSQL 13 | Speedup |
|---|---|---|---|
| 0 | 38 µs | 83 µs | 2.2× |
| 1 000 | 38 µs | 768 µs | 20× |
| 10 000 | 34 µs | 6 838 µs | 201× |
WHERE (created_at, id) < ($1, $2) ORDER BY created_at DESC, id DESC LIMIT 10The idiomatic “Markus Winand” keyset pattern, now supported natively in Nano v3.12:
| Cursor | HeliosDB Nano 3.12 | PostgreSQL 13 | Speedup |
|---|---|---|---|
| middle of 100k rows | 33 µs | 10 369 µs | 314× |
Three things, in order of impact:
offset-th matching key without decoding the bincode tuple, decrypting the page, or resolving dictionary / content-addressed references. On PostgreSQL, every skipped tuple still pays for MVCC visibility checks and heap-tuple decoding.sql::executor::topk::TopKOperator). When the plan is Limit(Sort(…)), Nano streams the input through a bounded heap of size k = limit + offset — O(N log k) instead of O(N log N), O(k) memory instead of O(N).(created_at, id) < ($1, $2)) is a first-class operator, not a macro-expansion into created_at < $1 OR (created_at = $1 AND id < $2). That means the planner and the evaluator both see the tuple directly, which opens the door to future index-range pushdown.Every number on this page comes from the bundled bench script. It uses the standard PostgreSQL wire protocol, so it runs unchanged against Nano, PostgreSQL, CockroachDB, YugabyteDB, or anything else that speaks PG wire.
git clone https://github.com/dimensigon/HDB-HeliosDB-Nano
cd HDB-HeliosDB-Nano
pip install 'psycopg[binary]'
# Against HeliosDB Nano (Unix socket, 100k rows)
./target/release/heliosdb-nano start --memory \
--pg-socket-dir /tmp --port 5432 &
python3 benches/external/pagination_bench.py \
--host /tmp --port 5432 --user postgres --dbname heliosdb \
--name "HeliosDB Nano" --rows 100000 --out nano.json
# Against PostgreSQL
PGPASSWORD=postgres python3 benches/external/pagination_bench.py \
--host localhost --port 5432 --user postgres \
--name "PostgreSQL 16" --rows 100000 --out pg.json
# Side-by-side
python3 benches/external/pagination_bench.py --compare nano.json pg.json
For Oracle or MS SQL Server, use the same queries through the respective native CLI (sqlplus or sqlcmd) with a timer wrapper — we haven’t bundled the proprietary drivers, but the shapes are identical and easy to port.
The “leads table with filters” page stays sub-millisecond at page 1 000. No keyset migration needed — just LIMIT/OFFSET.
Invoice search, order history, audit log — all the “paginate with joins” endpoints run at keyset-speed even with offset.
Django admin, Rails admin, React Admin — drop Nano in behind postgresql://, get constant-time paging without changing a line of framework code.
Drop the try/except wrappers and Python-side slicing. .limit(N).offset(M) just works at SQL speed, for any M.
OFFSET is O(M) heap-tuple decodes) is the same in PG 14/15/16, but exact numbers differ — expect a 10–30 % improvement on newer PG. The qualitative shape (linear growth with offset) is unchanged.fsync on PostgreSQL to level the bulk-seed time — the metric we care about is read latency, so the flag doesn’t affect the measured numbers, but it’s disclosed for completeness.Numbers generated on 2026-04-17. Benchmark script: benches/external/pagination_bench.py. HeliosDB Nano v3.12.0 release build.
Drop-in PostgreSQL / MySQL wire compatibility. Your ORM, your queries, your framework — no code changes. Just faster.