News for hackers. Stuff that matters.
Re:Unexpected downsides of UUID keys in PostgreSQL by jongjong on Thursday June 22, 2023 @07:58AM (#36430776)
I can't think of many use cases where I would sacrifice the beauty and elegance of UUIDs to optimize access times by a millisecond or two. UUID is totally worth the cost.

UUID actually performs much better than I thought based on the author's example with a COUNT query. COUNT queries aren't very efficient because typically, all records are traversed; here we're talking about a 50% slowdown on 10 million records... How often do you need to access 10 million contiguous records? Most of the time, for user-facing apps, you'll be accessing 100 contiguous records at most and, in fact, most queries will access a single record... I suspect that the average per-query performance loss for a typical app is probably less than 5%. Also, you could simply index by a separate date/timestamp field if you need records to be ordered by time and probably won't incur any performance cost.

IMO, unless you're building an app for high-frequency trading, auto-incrementing IDs aren't worth the pain and lack of flexibility.

Re:Unexpected downsides of UUID keys in PostgreSQL by whack on Thursday June 22, 2023 @08:44AM (#36431279)
> The moral of the story is that data locality matters, and it can pop up in the most surprising of places. Using random is typically the worst thing you can do for locality, so if you want to use UUID’s, try to use a sequential variant. UUID v7 is a good option

The author isn't suggesting abandoning UUIDs, he is suggesting using something like UUIDv7 which preserves locality. For most use-cases, this seems like a very reasonable recommendation with no significant downsides I can think of.

Re:Unexpected downsides of UUID keys in PostgreSQL by fauigerzigerk on Thursday June 22, 2023 @09:21AM (#36431748)
I agree that UUIDv7 will usually be the best choice. The one downside I can think of is that it may sometimes be necessary to let people know the identity of a thing without also telling them exactly when that thing was created.
Re:Unexpected downsides of UUID keys in PostgreSQL by pkilgore on Thursday June 22, 2023 @09:56AM (#36432241)
COMB UUIDs can help here.
Re:Unexpected downsides of UUID keys in PostgreSQL by fauigerzigerk on Thursday June 22, 2023 @12:37PM (#36434786)
Why do COMB UUIDs not have this problem? Do they not contain a timestamp?
Re:Unexpected downsides of UUID keys in PostgreSQL by pkilgore on Friday June 23, 2023 @05:38PM (#36452489)
It just orders ids based on a monotonic clock that wraps after a certain time -- it's enough to get a lot of of the performance benefit of ordered keys without directly exposing the unix wall clock time they were created (absent a dedicated attacker with the ability to create ids without you picking up on it for a timing attack, I suppose).

Whether that tradeoff makes sense probably depends.

Re:Unexpected downsides of UUID keys in PostgreSQL by remram on Thursday June 22, 2023 @10:47AM (#36432960)
Encrypt it. Block ciphers are bijective so they will turn sequential IDs into unique random IDs in a way you can easily reverse.

You can also do that to get opaque identifiers from an auto-increment primary key.

Re:Unexpected downsides of UUID keys in PostgreSQL by fauigerzigerk on Thursday June 22, 2023 @12:04PM (#36434283)
Seems awfully complicated to me.
Re:Unexpected downsides of UUID keys in PostgreSQL by jongjong on Thursday June 22, 2023 @08:17AM (#36430974)
Recently, I wrote a client-side wallet app for cryptocurrency use case and it required transactions to be created and signed entirely on the client-side and so the transaction UUID had to be created on the client side (before signing) and I was surprised at how elegant and simple the application's logic turned out to be (both on the front end and back end).

One of the best things about UUIDs is that if your front end tries to create a resource and fails due to a bad connection, you can simply resend that exact same resource for creation again (with the same UUID) and you don't need to worry about duplicate records being inserted into the database since you would get an ID collision; it results in much simpler/cleaner code which is idempotent and deterministic by default.

With auto-incrementing IDs, if there is a connection issue or other failure, it's not possible to easily figure out if a resource was already created or not since only the database knows what the ID of that resource was; the client doesn't know it until the resource has been successfully created in the database and the ID was send back to the client.

Just because the client did not receive a successful response from the server, it does not mean that the resource was not created; and if it was, you cannot know since the client has no way of referencing that resource in a unique way. It just seems completely wrong that the client (which created the resource) cannot reference it until the database has inserted it.

It's a hack to pretend that resource creation starts in the database, when in fact, it starts on the front end.

Re:Unexpected downsides of UUID keys in PostgreSQL by gradys on Thursday June 22, 2023 @08:47AM (#36431315)
You can achieve this without UUID keys if you attach UUIDs to the requests. This has the advantage of working for all kinds of mutating requests, not just creates, but requires that you store these request UUIDs for some period of time as well.
Re:Unexpected downsides of UUID keys in PostgreSQL by jongjong on Thursday June 22, 2023 @09:04AM (#36431527)
It's still not as elegant because it doesn't work in a multi-process or multi-server back end; if the request fails, you need to make sure that the retry request will hit the same server process (assuming you're keeping the UUIDs in memory on the server). You can use some in-memory data store like Redis to share the request UUIDs across multiple processes/hosts but that can add a lot more complexity, latency and risks and is just not worth it IMO.

Even in a single-host setup, it can be a problem because what happens if your process crashes and restarts just after a resource was created in the database but before the ID was sent to the client (with success message)? You would end up with a duplicate record in your DB after the retry since your newly restarted server would not have the UUID in its memory (even though the resource was in fact already created on the server a few milliseconds before the last crash).

With the Redis (or similar) solution, you need to make sure that the request UUIDs expire after some time and are cleaned up to avoid memory bloat which is a pain... I mean that complex solution probably uses up a lot more resources than just using UUIDs in the database as IDs.

Re:Unexpected downsides of UUID keys in PostgreSQL by ramchip on Thursday June 22, 2023 @09:29AM (#36431862)
You can use the DB for this as well, just make a table e.g. "requests" with two columns, the user and the request token. Old entries can be purged on a cron job.

If you add a column to store params as well then you can also do better validation:

> Responding when a customer changes request parameters on a subsequent call where the client request ID stays the same

> We design our APIs to allow our customers to explicitly state their intent. Take the situation where we receive a unique client request token that we have seen before, but there is a parameter combination that is different from the earlier request. We find that it is safest to assume that the customer intended a different outcome, and that this might not be the same request. In response to this situation, we return a validation error indicating a parameter mismatch between idempotent requests. To support this deep validation, we also store the parameters used to make the initial request along with the client request identifier.

https://aws.amazon.com/builders-library/making-retries-safe-...

Re:Unexpected downsides of UUID keys in PostgreSQL by jongjong on Thursday June 22, 2023 @10:10AM (#36432443)
You can but you add an additional database lookup step which will cost you more in performance (and latency) than just using UUIDs as the ID directly with a single table.
Re:Unexpected downsides of UUID keys in PostgreSQL by ramchip on Thursday June 22, 2023 @05:53PM (#36439592)
It's only at creation time. When you lookup the record after that you can use the ID directly, and then you don't hit the locality problems from the article.
Re:Unexpected downsides of UUID keys in PostgreSQL by dewey on Thursday June 22, 2023 @08:26AM (#36431082)
> sacrifice the beauty and elegance of UUIDs

Out of curiosity, what makes UUIDs more elegant or beautiful than just plain old integers?

Re:Unexpected downsides of UUID keys in PostgreSQL by kogus on Thursday June 22, 2023 @08:31AM (#36431140)
“5” might be the key for a thousand different records in your database. A uuid is a key for exactly one. Integer keys permit wrong joins to have the appearance of working.
Re:Unexpected downsides of UUID keys in PostgreSQL by totalhack on Thursday June 22, 2023 @08:37AM (#36431207)
You can incorrectly join on any columns you want. That's not really the fault of the column types IMO, that's a problem in the layers above.
Re:Unexpected downsides of UUID keys in PostgreSQL by dpcx on Thursday June 22, 2023 @08:46AM (#36431297)
True, but you can't incorrectly join on UUID due to its anti-collision nature.
Re:Unexpected downsides of UUID keys in PostgreSQL by ibash on Thursday June 22, 2023 @11:18AM (#36433472)
Yes you can, you’ll not get the correct result set.
Re:Unexpected downsides of UUID keys in PostgreSQL by OJFord on Thursday June 22, 2023 @02:48PM (#36436907)
As sibling says, you can make exactly the same mistake and it not colliding just means no join - but if it's an outer join and one of many joins or in a nested query it might not be immediately obvious it's happened, or what the issue is even if it is.
Re:Unexpected downsides of UUID keys in PostgreSQL by FroshKiller on Thursday June 22, 2023 @08:54AM (#36431404)
Crucially, "5" might also be the key to a thousand different records in dozens of other development & QA databases for applications with integrations configured incorrectly. Integers can match coincidentally. UUIDs won't.
Re:Unexpected downsides of UUID keys in PostgreSQL by Phil_Latio on Thursday June 22, 2023 @09:24AM (#36431793)
> Integer keys permit wrong joins to have the appearance of working.

How do you justify such an argument in the real world without people looking at you in disgust? This is the dumbest argument I've ever heard.

Re:Unexpected downsides of UUID keys in PostgreSQL by allknowingfrog on Thursday June 22, 2023 @09:54AM (#36432202)
That's not a very constructive response. UUIDs do provide global uniqueness, which can occasionally make mistakes more obvious. Do you have a counter argument to support your strong objection?
Re:Unexpected downsides of UUID keys in PostgreSQL by magicalhippo on Thursday June 22, 2023 @09:55AM (#36432220)
While wrong joins is a weak argument IMHO, our customers somewhat frequently ask to merge data, either from test to prod or from one company to another (after acquisition f.ex.).

In a lot of cases that can be a pain due to overlapping integer primary keys and large parent-child table sets.

Re:Unexpected downsides of UUID keys in PostgreSQL by antifa on Thursday June 22, 2023 @02:09PM (#36436319)
You can tell all your tables to use the same sequence.
Re:Unexpected downsides of UUID keys in PostgreSQL by smolder on Thursday June 22, 2023 @02:14PM (#36436386)
We have some app generated internal IDs which have a 1 character prefix by type and then base64 sequential stuff after that. I'll admit it's nice knowing the type of an identifier by looking at it. I don't really like that they are strings, however. The original architect made some weird choices as far as deciding where and where not to optimize for performance.
Re:Unexpected downsides of UUID keys in PostgreSQL by ceeam on Thursday June 22, 2023 @08:29AM (#36431121)
Their uniqueness of course.

> To be able to generate keys independently of the database

> To move sets of related records between different databases without having to deal with renumbering everything

Re:Unexpected downsides of UUID keys in PostgreSQL by yes_man on Thursday June 22, 2023 @08:36AM (#36431202)
And adding greppability of logs in debugging situations. You can just search logs in any systems of yours with the UUID and find exact hits you are dealing with. Whereas with integers you will get all kinds of hits
Re:Unexpected downsides of UUID keys in PostgreSQL by phkahler on Thursday June 22, 2023 @09:37AM (#36431975)
Because UUIDs are universally Unique IDentifiers.
Re:Unexpected downsides of UUID keys in PostgreSQL by jandrewrogers on Thursday June 22, 2023 @06:07PM (#36439789)
Unfortunately, UUIDs aren't as universally unique in practice as people think. The standard flavors are banned in quite a few organizations that care a lot about data integrity for valid reasons. Standard UUIDs work for some applications but definitely not all.

For most applications you are better off using a sensible structured key, like incrementing an integer or similar, and encrypting it if you want to obscure it. Encrypting a 128-bit value is approximately free on modern CPUs.

Re:Unexpected downsides of UUID keys in PostgreSQL by maxgee on Thursday June 22, 2023 @08:29AM (#36431116)
Nothing. Integers are simpler and faster. They're also incorrect about COUNTs requiring a full record scan.
Re:Unexpected downsides of UUID keys in PostgreSQL by xkqd on Thursday June 22, 2023 @08:34AM (#36431172)
How are integers simpler? Even generation of unique integers is more complicated, let alone migrating them or moving them around.
Re:Unexpected downsides of UUID keys in PostgreSQL by phito on Thursday June 22, 2023 @08:50AM (#36431342)
Nothing? Really? Have you ever thought about that?
Re:Unexpected downsides of UUID keys in PostgreSQL by catlifeonmars on Thursday June 22, 2023 @12:41PM (#36434875)
* * *
Re:Unexpected downsides of UUID keys in PostgreSQL by Raz2 on Thursday June 22, 2023 @11:23AM (#36433560)
> To be able to generate keys independently of the database

This is a must if you don't want to couple your domain logic and DB. I want to generate a record with an ID inside my domain layer without depending on the DB and doing awkward DB save - DB read.

Re:Unexpected downsides of UUID keys in PostgreSQL by pgaddict on Thursday June 22, 2023 @08:49AM (#36431338)
It is not a matter of a couple milliseconds.

The loss of locality for reads is bad, especially for data sets that don't fit into cache / RAM (while the active set would).

Where it really bites you is writes, because it can trigger pretty massive write amplification.

Imagine you have 128 GB index on UUID column, that's ~16M pages (8kB) and insert 1M random values. Congrats! You've probably just wrote 8GB to the WAL, because of FPW and stuff like that. With serial IDs we'd write a fraction of that. It doesn't take much to hit max_wal_size and trigger a checkpoint, starting a new cycle with FPWs. Got a replica? Well, now you need to send the WAL over network. Is the bandwidth limited (another DC?), sorry to hear that. Is the replica sync and you have to wait. Well, that's unfortunate.

In other words, the lack of locality seems like a detail but at scale it's actually a damn huge deal.

Re:Unexpected downsides of UUID keys in PostgreSQL by catlifeonmars on Thursday June 22, 2023 @09:20AM (#36431740)
At scale you’re probably sharded across multiple DBs and you’re already operating through replicas. Point being you’re less likely to hit a warm cache as you scale up anyway as your application layer gets load balanced to different DB endpoints.
Re:Unexpected downsides of UUID keys in PostgreSQL by jongjong on Thursday June 22, 2023 @09:42AM (#36432029)
Yes exactly, with proper sharding, raw performance is not as important; to some extent, you trade it away for improved concurrency. In fact, I struggle to see how one would implement sharding with auto-incrementing integers (you would get ID collisions for different resources across different shards/database instances); there needs to be a way to uniquely refer to resources across potentially multiple databases and UUIDs are one of the best ways to achieve that.

Auto-incrementing IDs simply don't scale beyond a single host so I don't see how they can be good for scalability. Too many devs conflate raw performance with scalability. They are not the same at all - In fact, high scalability often incurs a performance overhead.

Re:Unexpected downsides of UUID keys in PostgreSQL by coredog64 on Thursday June 22, 2023 @10:05AM (#36432380)
We did auto-increment integers with multiple servers like 20 years ago: The caveat is that you have to know how many servers are in the set in advance. Each server increments by the population size, and their starting number is their position within the pool.

Not hyper scale, but good enough for failover or a 3-5 node setup.

Re:Unexpected downsides of UUID keys in PostgreSQL by egeozcan on Thursday June 22, 2023 @10:35AM (#36432777)
Hi/Lo algorithm also works fine for most cases
Re:Unexpected downsides of UUID keys in PostgreSQL by viraptor on Thursday June 22, 2023 @10:13AM (#36432470)
Or increment by more than you need. If you think you'll only ever have 5 nodes, increment by 20. Lots of space for expansion and in practice you'll hit the datatype limits just a bit earlier - you'd need to work around them anyways.
Re:Unexpected downsides of UUID keys in PostgreSQL by ilyt on Thursday June 22, 2023 @12:04PM (#36434290)
IIRC that's what MySQL Galera is doing by default

    mysql> CREATE TABLE animals (
        ->      id MEDIUMINT NOT NULL AUTO_INCREMENT,
        ->      name CHAR(30) NOT NULL,
        ->      PRIMARY KEY (id)
        -> );
    Query OK, 0 rows affected (0.34 sec)
    
    mysql> INSERT INTO animals (name) VALUES
        ->     ('dog'),('cat'),('penguin'),
        ->     ('lax'),('whale'),('ostrich');
    Query OK, 6 rows affected (0.01 sec)
    Records: 6  Duplicates: 0  Warnings: 0
    
    mysql> SELECT * FROM animals;
    +----+---------+
    | id | name    |
    +----+---------+
    |  3 | dog     |
    |  6 | cat     |
    |  9 | penguin |
    | 12 | lax     |
    | 15 | whale   |
    | 18 | ostrich |
    +----+---------+
    6 rows in set (0.00 sec)
Re:Unexpected downsides of UUID keys in PostgreSQL by catlifeonmars on Monday July 03, 2023 @02:22PM (#36576921)
Oh this is clever! I guess it’s actually very similar conceptually to a vector clock. (In that you have partitioned the space of natural numbers into K countably infinite sequences).

If you wanted to (practically speaking anyway) overcome the requirement that K is known, you could borrow prefix based counting from the p-adics.

Re:Unexpected downsides of UUID keys in PostgreSQL by pgaddict on Thursday June 22, 2023 @01:30PM (#36435715)
I respectfully disagree with the notion that sharding makes resource usage somehow less important. Sure, it allows you to overcome the limits that would apply to a single node, but if you stop caring about using resources efficiently (e.g. memory / disk / network bandwidth), it's not very different from building huge and expensive single boxes.

Also, I don't think the blog (or me) suggested going back to using autoincrement IDs. There are other (better) options.

Re:Unexpected downsides of UUID keys in PostgreSQL by magicalhippo on Thursday June 22, 2023 @09:50AM (#36432153)
Reminds me of a talk about ZFS performance, where they presented some benchmark results showing that as the number of concurrent clints doing pure sequential IO increases, the more the load appears as random IO to the filesystem.

So with high enough concurrent load it's effectively all random IO and that's the primary thing worth optimizing for.

Re:Unexpected downsides of UUID keys in PostgreSQL by ok123456 on Thursday June 22, 2023 @09:19AM (#36431730)
Then just make a generated column that's a 32bit integer hash of the uuid for this particular case and create an index on that? Use that during expensive queries that blow up your cache locality if it matters.
Re:Unexpected downsides of UUID keys in PostgreSQL by insanitybit on Thursday June 22, 2023 @09:24AM (#36431796)
A 32bit integer hash won't have locality either.
Re:Unexpected downsides of UUID keys in PostgreSQL by ok123456 on Thursday June 22, 2023 @09:34AM (#36431937)
Ok. Pick a resolution where you won't get collisions and that is a native datatype.
Re:Unexpected downsides of UUID keys in PostgreSQL by patrec on Thursday June 22, 2023 @11:04AM (#36433235)
I feel that you don't understand what locality is about: the property of IDs that were generated closely together in time to be close together numerically. You don't get that by "hashing" the UUID (which makes no sense anyway, since you might as well just take some truncation of the UUID). In fact the whole idea behind a hash is to destroy this property of the input data. The reason the numerical locality matters is that it is much more efficient to in-sequence-insert several numbers that are close together into an index than to in-sequence-insert the identical amount of randomly distributed numbers.

The GP was talking about the first graph here: https://www.2ndquadrant.com/en/blog/on-the-impact-of-full-pa...

Re:Unexpected downsides of UUID keys in PostgreSQL by ok123456 on Thursday June 22, 2023 @11:06AM (#36433274)
I thought you were talking about cache locality within the CPU. Real cache locality.

If you care about the insert location, why not just add a brin index on a timestamp field and use that instead of assuming that the index is sequential.

Re:Unexpected downsides of UUID keys in PostgreSQL by insanitybit on Thursday June 22, 2023 @12:27PM (#36434628)
CPU cache locality is not "real cache locality", it is just another place where caches exist and locality is optimized for. Your solution wouldn't work for CPUs either, other than that you could fit more data that isn't spatially correlated into a cache line.
Re:Unexpected downsides of UUID keys in PostgreSQL by patrec on Thursday June 22, 2023 @01:17PM (#36435506)
How would adding a BRIN index help in any way with reducing the discussed problems, such as write amplification?
Re:Unexpected downsides of UUID keys in PostgreSQL by pgaddict on Thursday June 22, 2023 @01:45PM (#36435942)
This is a bit confusing, as it mixes two things - BRIN index and index on a timestamp.

The main source of write amplification comes from updating random pages of the btree index. Imagine inserting 10 random UUID values into a large index - it's pretty likely those will go into 10 different leaf pages. And every first update of a page after a checkpoint (which typically happens every 30 minutes or so), we have to write a FPI (i.e. the whole 8kB page) to WAL. So because btrees are based on ordering, random values end up on random leaf pages, causing write amplification.

If you have BRIN index on UUID column, this does not happen, because the index is not based on ordering but location in the table. If the 10 rows get appended to the same table page, that'll be just 1 write, with one FPI.

This is why BRIN does not have the write amplification issue. But it's also a bit pointless, because BRIN on random data is pretty useless for querying (Well, at least the minmax indexes, are. Let's ignore BRIN bloom indexes here.)

If you create BRIN on timestamp, that's not going to have write amplification problem, and it'll be good for querying. The thing is - BTREE would not have write amplification problem either, because the timestamps are going to be sequential (hence no updates to random leaf pages).

Re:Unexpected downsides of UUID keys in PostgreSQL by saltcured on Thursday June 22, 2023 @02:36PM (#36436741)
Right, you just need to avoid having the btree index on the UUID field. Similarly, don't pose queries to sort by the randomized UUID field either. This is where the often maligned hash index type could be useful, to allow lookup of individual rows by UUID without all the expense of a btree index maintenance. Use other fields for ordering that have better write locality.

What this means in practice, of course, is that you shouldn't expect to do application driven pagination with UUID keys either. You would need to expose some other boundary marker with a total order that works well with btrees. And this could bring you back to "leaking" predictable key material that you were trying to hide by adopting UUIDs...

Re:Unexpected downsides of UUID keys in PostgreSQL by insanitybit on Thursday June 22, 2023 @12:26PM (#36434612)
Hashes evenly distribute information regardless of the input. You will never have locality unless your dataset is so small that all of it can fit into a single cache line.

Your solution just doesn't really make any sense. The time ordered UUID suggested in the blog post makes way more sense.

Re:Unexpected downsides of UUID keys in PostgreSQL by unshavedyak on Thursday June 22, 2023 @11:06AM (#36433268)
Out of my scope, but why are UUIDs even discussed? ULIDs (and i think Nanoids?) don't suffer these same problems. Locality and ordering alone make me[1] think ordered ULIDs (and friends) are the only thing worth discussing.

Is there some value to UUIDs over ULIDs that make these discussions largely revolve around Autoincrement vs UUIDs rather than Autoincrement vs ULIDs(and friends)?

[1]: Again, totally out of my wheel house.

edit: Apparently UUIDv7 exists, which is similar to ULID, so my question pertains to UUIDv5 and below, i think.

Re:Unexpected downsides of UUID keys in PostgreSQL by xahrepap on Thursday June 22, 2023 @11:41AM (#36433888)
ULIDs have made our MySql caches breathe a sigh of relief.

One place we're avoiding ULIDs (and other counters) is in publicly-facing IDs. Preferring random to help keep them unguessable. (say what you will about security-through-obscurity).

So we do ULIDs for private IDs. Random UUIDs for public IDs. Seems to work well.

Re:Unexpected downsides of UUID keys in PostgreSQL by ilyt on Thursday June 22, 2023 @12:02PM (#36434249)
I wonder if just encrypting them for public usage would be enough here. Then application can convert between public and private representation at will.
Re:Unexpected downsides of UUID keys in PostgreSQL by selcuka on Thursday June 22, 2023 @11:18PM (#36442388)
Encryption is good until someone leaks the private key. Depending on the application, it may be very difficult to reassign all primary keys and foreign keys when that happens, especially if they have already been used as canonical identifiers.

You don't have such issues with randomly generated ids, unless someone obtains a full dump of your database (in which case you will have to think about bigger problems anyway).

Re:Unexpected downsides of UUID keys in PostgreSQL by smaddox on Thursday June 22, 2023 @03:00PM (#36437088)
KSUID's are have temporal-lexicographical order plus 128 bits of entropy, which is more than UUIDv4.

https://github.com/segmentio/ksuid

Re:Unexpected downsides of UUID keys in PostgreSQL by ljm on Thursday June 22, 2023 @11:34AM (#36433754)
I’ve worked with ULIDs a bit but honestly haven’t operated at a scale where you might run into issues. And the main reason for choosing ULID was because I could only find experimental support for UUIDv6 or UUIDv7, and KSUID (another alternative) only had time precision down to a second.

And the reason for that was to have lexicographically sortable IDs (even if not monotonic, which would require an extra server) so we didn’t have to index a timestamp column for chronological ordering. The alternative was to have a traditional integer sequence but it’s not always ideal to expose those on your API.

Re:Unexpected downsides of UUID keys in PostgreSQL by cratermoon on Thursday June 22, 2023 @12:26PM (#36434598)
Out of curiosity, why do your keys need time precision less than a second? Are they carrying some secondary expectations beyond uniqueness and k-sortable?
Re:Unexpected downsides of UUID keys in PostgreSQL by ljm on Wednesday June 28, 2023 @04:15PM (#36511960)
Uniqueness and the context is that we were modelling a chat conversation, so the limited precision presented issues with messages occasionally appearing out of order.

That also applied to our test suite so the choice was to use KSUID but still index a timestamp for accuracy, or just use an alternative with more precision.

Re:Unexpected downsides of UUID keys in PostgreSQL by esafak on Wednesday June 28, 2023 @04:56PM (#36512468)
What would you use for that application if you had to choose today?
Re:Unexpected downsides of UUID keys in PostgreSQL by letitbeirie on Thursday June 22, 2023 @11:21AM (#36433514)
Postgres supports UUIDs natively
Re:Unexpected downsides of UUID keys in PostgreSQL by unshavedyak on Thursday June 22, 2023 @11:29AM (#36433671)
Is that worth the pain of dealing with randomized inserts? I guess i just don't mind creating a ULID (or i guess UUIDv7 is newly proposed and sortable) and inserting that.

Native DB support is irrelevant to me for randomized bits unless it affects storage, sorting, paging, etc. Does it?

Re:Unexpected downsides of UUID keys in PostgreSQL by code-e on Thursday June 22, 2023 @02:12PM (#36436366)
It does affect storage and sorting. A native UUID type uses 16 bytes. The alternative is text encoding (32 bytes for hex), or maybe a raw BYTEA. Postgres also has SortSupport for the UUID type, which basically means if the first 8 bytes only has one matching row, then the remaining 8 bytes can be skipped. Combine that with a ULID where the most first half is basically a timestamp, you'll get performance close to using a single 8byte BIGSERIAL.

You can also write a plpgsql function to generate these ULIDs in the database.

Re:Unexpected downsides of UUID keys in PostgreSQL by lolinder on Thursday June 22, 2023 @01:57PM (#36436139)
ULIDs are byte-compatible with UUIDs, so the only thing Postgres's native support gives you over ULIDs is that Postgres can generate new UUIDs for you instead of having to do it in the application before insertion.
Re:Unexpected downsides of UUID keys in PostgreSQL by letitbeirie on Thursday June 22, 2023 @06:11PM (#36439819)
It also buys you that support in the driver libraries.

I ran into this last year - storing them as UUIDs works great, unless all of the drivers for the language you're using (Go, in my case) try to cast/validate those bytes as a UUID before you can access them.

Re:Unexpected downsides of UUID keys in PostgreSQL by qaq on Thursday June 22, 2023 @11:16AM (#36433440)
this sounds horrible until you realise that a modern SSD will write that in about 1.5 sec.
Re:Unexpected downsides of UUID keys in PostgreSQL by pgaddict on Thursday June 22, 2023 @01:06PM (#36435346)
That was just an example calculation, to illustrate the write amplification factor, of course. You can scale it up pretty arbitrarily.

I mentioned only WAL for simplicity, but it also has to modify and write out the index pages themselves, and write them out eventually. And that's going to be mostly random I/O. Flash storage is good at handling that, ofc, but if things are adding up like this ...

Not to mention you still have to copy the WAL over network to replica, or perhaps to multiple replicas. And if you have physical backups with PITR, you gotta keep all the WAL somewhere too.

Re:Unexpected downsides of UUID keys in PostgreSQL by qaq on Thursday June 22, 2023 @02:16PM (#36436430)
sure but not many workloads are writing out million inserts per second.
Re:Unexpected downsides of UUID keys in PostgreSQL by uppiiii765 on Thursday June 22, 2023 @11:52AM (#36434087)
Mmmhhh should that not be highly efficient for flash based storage?
Re:Unexpected downsides of UUID keys in PostgreSQL by nine_k on Thursday June 22, 2023 @12:27PM (#36434622)
If you want locality, speed, simplicity, etc above all, use an incremented integer and be done with it.

UUIDs belong where you can't afford that simplicity. Where you e.g. cannot coordinate the creation of your primary keys. Or where you cannot allow them to be predictable. There you pay the price.

In practice I noticed that the size of PKs and their poor locality start to play a role only after a huge basket of lower-hanging fruit has been collected. There are relatively few places where their role is dramatic.

Re:Unexpected downsides of UUID keys in PostgreSQL by gregmac on Thursday June 22, 2023 @12:37PM (#36434785)
> UUIDs belong where you can't afford that simplicity. Where you e.g. cannot coordinate the creation of your primary keys. Or where you cannot allow them to be predictable. There you pay the price.

You often don't realize you you have non-simple needs until your application is reasonably mature, and in production. If you already picked integer keys, you now either forever deal with the issues caused by not using UUIDs, or you deal with the unknown-but-non-zero pain of converting to UUIDs.

Re:Unexpected downsides of UUID keys in PostgreSQL by esafak on Wednesday June 28, 2023 @05:06PM (#36512607)
The age old startup bargain: do you want to pay a small cost up front, or a large one later? If only you'd seen it coming!
Re:Unexpected downsides of UUID keys in PostgreSQL by marcosdumay on Thursday June 22, 2023 @01:18PM (#36435520)
> Where you e.g. cannot coordinate the creation of your primary keys.

You are writing your data into a DBMS. Coordinating the creation of primary keys is one of the cheapest tasks around, if you can't do that, how is your database still online?

> Or where you cannot allow them to be predictable.

You don't need to export your PKs for the rest of the world. You can have non-predictable data outside of your PK. Yes, a different column will still have some of the problems with index maintenance, but it becomes a much smaller problem if only one table cares about the value.

Re:Unexpected downsides of UUID keys in PostgreSQL by nine_k on Thursday June 22, 2023 @01:44PM (#36435925)
You can almost always opt for artificial PKs that are more performant.

But sometimes you have to make these keys public, e.g. as user or other resource IDs. You want to make them UUIDs so they won't be predictable. Not having to join everywhere with the UUID-to-artificial-PK table may be a bigger performance win than the losses from larger size of UUIDs.

Sometimes you have a distributed / sharded system, and don't want the keys to clash, and also avoid assigning ranges. Sometimes you have to accept someone else's ID, not originating in your system. In cases like that, large random numbers, e.g. UUID v4, work reasonably well.

Of course when you just have one DB, and a relative slow stream of new rows, it's easy to fully control PK creation. And this covers the majority of practical cases.

Re:Unexpected downsides of UUID keys in PostgreSQL by jgraettinger1 on Thursday June 22, 2023 @01:57PM (#36436137)
We use a macaddr8 that embeds a wall-clock timestamp (so they're ascending order, achieving data locality) with some additional shard and sequence-number bits. It's worked really well for us:

https://github.com/estuary/flow/blob/master/supabase/migrati...

we use macaddr8 instead of bigint, because it has a postgres serialization / JSON encoding which lossless-ly round-trips with browsers and it works well with PostgREST. The same CANNOT be said for bigint, which is a huge footgun.

Re:Unexpected downsides of UUID keys in PostgreSQL by turnsout on Thursday June 22, 2023 @09:25AM (#36431810)
Yes—this entire article could be "If you use UUID ids, index your 'created on' field"
Re:Unexpected downsides of UUID keys in PostgreSQL by danpalmer on Thursday June 22, 2023 @09:32AM (#36431904)
> I can't think of many use cases where I would sacrifice the beauty and elegance of UUIDs...

I find auto-incrementing IDs far more elegant in many ways. They are much easier to make sense of for users, they give you some loose metadata (ordering, sometimes a rough time range) which can be handy in debugging stuff.

At my previous workplace most things were auto-incrementing IDs, and while we got bitten by them a few times, there was significant debugging value in seeing a user ID as an integer. Internally, order IDs and customer support ticket IDs were also auto-incrementing, but we offset them so that even numbers were orders and odd numbers were support tickets, and this helped quite a bit with debugging or even just non-technical users sending each other references. Not that this can't be done with prefixes on UUIDs with a bit of extra work.

I wouldn't necessarily recommend auto-incrementing IDs or UUIDs over the other, but I don't think one is more elegant at all.

> to optimize access times by a millisecond or two. UUID is totally worth the cost.

2ms * 20 queries is 40ms, which could take a typical page load for a web app from 150ms to 190ms, which is quite a regression.

Re:Unexpected downsides of UUID keys in PostgreSQL by biztos on Thursday June 22, 2023 @09:41AM (#36432018)
I'm a big fan of SERIAL and BIGSERIAL, for aesthetic/cognitive reasons more than performance, but it can be really nice to have a data-generating process generate the primary ID of a piece of data, which you can then log before you put it in the database and look up the same ID everywhere when debugging.

Not to mention the distributed database situation.

In fact I like that enough that I sometimes use ULIDs for secondary unique keys just so I have something to log, even if the primary key is numeric.

It's nice that you can store ULIDs in Postgres natively as UUIDs, and it's really nice to have a timestamp embedded in the ULID if you ever need it... but it's also really tempting to use it in public-facing stuff and thus leak your creation timestamp.

Re:Unexpected downsides of UUID keys in PostgreSQL by danpalmer on Thursday June 22, 2023 @10:10AM (#36432436)
Absolutely, these are also good things to take into account. There are really situations for all of these things, and this is why I don't like the approach of trying to "solve" this problem. Lots of people say "UUIDs solve IDs", or "UUIDs cause too many issues to use", or "ULIDs solve UUID issues", and in reality this is just another place where there are trade-offs, and what works for one company/project/dbms/table may not work for another, or may even cease to work over time as requirements or scale change.