Benchmark

The numbers behind the rules

Every rule page that says a change blocks traffic shows how long, from this run: the dangerous form and the safe form of the same change, on the same table, while two other sessions keep writing and reading. Nothing here is asserted from documentation; it is what the server did.

The setup

Postgres
18.6 (postgres:18-alpine)
Table
20M rows, 1.65 GB, orders with a bigserial key, an int, a text, a numeric and a timestamptz
Probes
one session inserting a row and one reading a row by key, every 50 ms, each call timed
Hardware
Apple M1 Max, 10 cores, 69 GB, darwin 25.5.0
Run
Sep 16, 2026, throwaway container, destroyed afterwards

Worst wait is the slowest single probe call while the statement ran. Lock modes are read from pg_locks before COMMIT for transactional forms and sampled every 100 ms otherwise; a rewrite is a change of the table's relfilenode. Laptop hardware, so the absolute times are small and the ratios are what matter.

Every scenario

One card per rule. The headline is how long ordinary traffic was stuck behind the change: the worst single insert or read while the statement ran, dangerous form first, safe form after the arrow. Below it, what each form was and how long the statement itself took.

"Refused" is the server rejecting the statement outright (a NOT NULL column with no default on a populated table); "gave up" is a lock_timeout doing its job. Both are the rule being right, not the bench failing. A form that takes as long as the dangerous one but blocks nobody (CONCURRENTLY) is the point: the time moves off the users. Rules with no scenario have nothing to time: destructive changes, type choices, credentials and set ordering are judged from the statement alone.

Run it yourself

The scenarios, the runner and this run's results are in the public repository under packages/engine/bench. One command with Docker present; the file it writes is what this page and the rule pages are built from.

git clone https://github.com/bolvrk/bolvrk
cd bolvrk && bun install
bun run bench                          # every scenario, 20M rows, postgres:18-alpine
bun run bench -- --rule BV003          # one rule
bun run bench -- --image postgres:18-alpine

Disagree with a number? The scenario is a few lines of SQL you can read and change; a pull request with a better one is the right reply. packages/engine/bench on GitHub