Case Study: Sessions and Reporting in One Store Instead of Two
A web application checks its session table on every request. A token comes in, and the app needs the user behind it, fast. Once in a while somebody wants a different view of the same data: how many sessions are live per country, or every session of one user, revoked at once when a password changes. Teams often split this in two, with sessions in Redis for speed and a copy in SQL for the reports and the bulk revokes.
This case study keeps both jobs in one KvSQL table and measures each. It’s a program in the repository, case_studies.rs, run by the project’s test script. The figures are from its recorded run of October 22, 2026, on a real file with every commit synced, on a Linux container with two virtual CPUs. The output is in case-studies.md.

The three jobs on one table, from the recorded run.
The Table
CREATE TABLE sessions (token TEXT PRIMARY KEY, user_id INTEGER NOT NULL,
country TEXT, expires INTEGER NOT NULL);
CREATE INDEX sessions_user ON sessions(user_id);
The program fills it with 100,000 sessions for 20,000 users across eight countries, in one transaction with put_row. That took 964 ms. Each row lands under its token in the table’s B+tree, and its user id goes into the index.
Per Request: The Key Door
The request path is one call:
let session = db.get_row("sessions", &Value::Text(token))?;
200,000 lookups of random tokens took 2.00 µs each, and every one found its row. The same lookups written as SELECT user_id FROM sessions WHERE token = ? took 4.10 µs each. Both read the same leaf page. The difference is the SQL work in between: the statement cache, the planner and building a result set.
For the Dashboard and the Revoke: SQL
SELECT country, count(*) FROM sessions WHERE expires > ? GROUP BY country ORDER BY 2 DESC, 1;
DELETE FROM sessions WHERE user_id = ?;
The dashboard query read all 100,000 rows and took 53.5 ms, counting 49,586 live sessions in eight countries. The revoke found user 4242’s five sessions through the index and deleted them in 1.7 ms, the synced commit included. A reader that had opened a snapshot before the delete still counted five sessions. That’s snapshot isolation doing its job: the report it was building stays consistent. Right after the commit, get_row on one of the revoked tokens found nothing. There was no second store to fall behind.
The program ends with verify, which walks every page and checks every row against its table and every index entry against its row. It passed, with 3,747 pages and 199,992 keys in the file.
What It Shows
One table served both kinds of work. The lookup path never touched SQL, and the reports never needed a copy. The revoke was a single transaction, so there was no window where a user’s sessions were half gone, and no sync job between two stores to write or watch.