Live data from Hacker News

The perils of UUID primary keys in SQLite

andersmurphy.com

71–80 of 117 posts

Re: The perils of UUID primary keys in SQLite

#71
post #63

This is actually a draft. I Wanted to add more details about how this changes with row size etc. I might get time to update it later today.

Maybe you could explain why one would use "without rowid" in the first place. I get saving 8 bytes per row seems attractive, but the tradeoff is not explained.

Update the article there's now a section for UUID4 with rowid. It's less bad than UUID4 without rowid but it's still about 4-6x slower than UUID7 without rowid.

Re: The perils of UUID primary keys in SQLite

#72
post #63

This is actually a draft. I Wanted to add more details about how this changes with row size etc. I might get time to update it later today.

Maybe you could explain why one would use "without rowid" in the first place. I get saving 8 bytes per row seems attractive, but the tradeoff is not explained.

The reason to use it is that it skips the double lookup. A normal rowid table with a UUID primary key keeps two B-trees: the table itself keyed by the hidden rowid, and a separate index from your UUID to that rowid. A lookup by UUID walks the index to find the rowid, then walks the table to find the row. WITHOUT ROWID makes the UUID the table's key directly, so the row sits in that leaf and you walk one tree instead of two, and you don't store the UUID a second time.

The tradeoff is what the benchmark is hitting. Once the table is physically ordered by the key, a random v4 scatters every insert across the tree and you pay for the page splits. A plain rowid table keeps that churn in the secondary index, which is just the key plus a rowid, while the table itself stays append-ordered. So it only really pays off when the key is something you look up directly and is roughly sequential, which is why v7 comes back near baseline.

Re: The perils of UUID primary keys in SQLite

#73

Earlier quoted context omitted.

> bigints are smaller and faster, with less footguns But be careful!! Javascript WILL interpret your bigints as Number() and round them down because they are too big without telling you!!! Famously seen by every snowflake user that has interacted with Javascript, quite an annoying problem.

Good trick is to prefix all such keys with magic, i.e. a couple of letters that identify type type of key. Then it will always be a string and you will be free to change the format/type of the key in the future to UUID or whatever you like.

Rule of thumb: if you’re not doing math with a value, it’s not a number.

Re: The perils of UUID primary keys in SQLite

#74
post #5

UUIDs are way over used. There is almost always a better key to use, usually a bigint for databases. If you're making some kind of leaderless distributed data store, then maybe, but even then there are other ID sharding strategies I'd go for first depending on the constraints. For a single database, bigints are smaller and faster, with less footguns. UUIDs can be nice for an opaque public ID, however I'd still prefer…

What are uuid foot guns?

Re: The perils of UUID primary keys in SQLite

#75
post #5

UUIDs are way over used. There is almost always a better key to use, usually a bigint for databases. If you're making some kind of leaderless distributed data store, then maybe, but even then there are other ID sharding strategies I'd go for first depending on the constraints. For a single database, bigints are smaller and faster, with less footguns. UUIDs can be nice for an opaque public ID, however I'd still prefer…

[deleted]

Re: The perils of UUID primary keys in SQLite

#76

Perils of “UUIDv4”. Everyone knows that’s what UUIDv7 was really for, and you should always convert that to binary to optimize everything.

Doesn't Postgres' UUID type just do this for you anyway?

Why would you store it as as str column and not the inbuilt type for this?

https://www.postgresql.org/docs/current/datatype-uuid.html

If you are using SQLite well I guess that doesn't work.

Re: The perils of UUID primary keys in SQLite

#77

Thanks for the benching, Anders! So grateful for the stuff you've shared over the years. Invariably, every single post has been useful and/or educational to me. I read this post more as an illustration of the *value* of UUIDv7 as primary key, over integer primary keys , in lieu of minimal loss of read/write performance, and marginally more data on disk bloat. SQLite's automatic integer rowID primary key is a no-brain…

I've updated the article with the correct rowid alias (integer not int) so the rowid version is now 715ms. I've also added an example of rowid and a secondary index UUID4, and that also seems to be bad for performance (as although it's not a clustered index it's still random inserts into a b-tree).

Re: The perils of UUID primary keys in SQLite

#78

So UUID isn't the problem but UUID v4 is, just like any random ID-scheme, correct? UUID v7 so far seems like the best solution if you want UUID benefits and ordering.

It's " WITHOUT ROWID" problem. Why would you force database to order rows on the drive according to random id?

If you had read the article, you'd have seen that UUIDv4 with Rowid was slightly slower than UUIDv7

Re: The perils of UUID primary keys in SQLite

#80
post #5

UUIDs are way over used. There is almost always a better key to use, usually a bigint for databases. If you're making some kind of leaderless distributed data store, then maybe, but even then there are other ID sharding strategies I'd go for first depending on the constraints. For a single database, bigints are smaller and faster, with less footguns. UUIDs can be nice for an opaque public ID, however I'd still prefer…

Providing an ID from the client is a big advantage that's missing though. Especially if you want a UI with optimistic rendering that's dealing with something async
Post reply on HN