Two bar charts of read cost at chain depth 60. Left, struck through in red: what my explanation predicted, oldest reader much taller than newest. Right: what the table already said, newest 1450 ns and oldest 1480 ns, equal, with the ratio 1.02 highlighted.

I Explained a Slow Read and Wrote It Down. The Ratio That Disproved It Was Already in the Table.

You have a benchmark that says something is slow. You also have an explanation for why, and it sounds right. If you have already written that explanation into a design note or a ticket, this post is about the one check I skipped before doing exactly that, and what it cost me. The system is minidb, a small relational database I wrote in Go to learn storage internals. The mistake would have happened with any benchmark that has two rows. ...

October 5, 2026 · 8 min · Hoang Nguyen Thai
Log-log chart: a dotted extrapolation line ending near 10 ms, two measured no-index curves far above it (MariaDB 10.11 at 968 ms and 13.0 at 148 ms at 1M rows), a dashed 300 ms threshold, and a flat under-1 ms line for the indexed case

I Wrote the Index Escalation Threshold as a Number, Then Measured It and Found It Off by 15x to 100x

Somewhere in a design document you have signed off on, there is a sentence of the form “when it passes X, we will do Y.” Has anyone ever generated X rows to check that the number means what it says? At the end of last month I signed off on a design that runs a lookup against a column with no index, on a table my team does not own, and wrote the condition for fixing it as a sentence with two numbers in it: “when the table passes about 1,000,000 rows or the p95 of the voucher filter passes 300 ms, request a non-unique index from the owning team.” The sentence had one job: get the option “ship without the index” through design review, with “we will add it later” turned into something a reviewer could sign. It did that job. ...

September 28, 2026 · 10 min · Hoang Nguyen Thai
UUIDv7 Structure and B-Tree Performance

UUIDv7: Why You Should Stop Using Auto-increment Integers and UUIDv4

The Challenge of Identifiers In software engineering, choosing a Primary Key type seems simple, but it profoundly affects both security and system performance as you scale. We typically start with two familiar choices: Auto-increment Integers or UUIDv4. 1. Limitations of Traditional Methods Option 1: Auto-increment Integer -- Example: Sequential IDs over time 1, 2, 3, 4, 5... Pros: Extremely fast and memory-efficient. Cons: Lack of security. If your URL is https://api.myapp.com/v1/invoice/1001, a competitor can easily guess that the next invoice is 1002, or even count your total customer base just by incrementing these numbers. Option 2: UUIDv4 (Random String) -- Example: No discernible order f47ac10b-58cc-4372-a567-0e02b2c3d479 0e58c3d4-a567-4372-58cc-f47ac10b0e02 Pros: Maximum security; impossible to predict. Cons: Database Fragmentation. Because it is entirely random, the Database must work hard to sort these into memory, slowing down the system as your data grows. 2. UUIDv7: The Best of Both Worlds UUIDv7 solves these problems by combining: [Current Timestamp] + [Random Bits]. ...

March 9, 2026 · 3 min · Hoang Nguyen Thai