I would like to know the general practice used in the industry for generating sequence numbers.
i.e. Get the max from a table. Increment it and store it back.
In order for this to work, which isolation level and/or locking scheme should be used.
I thought serializable should work fine. But it only prevents updates to a table. Selection can still be done. So, the value that would be updated could be same. How can we avoid this?
Thanks!
Anything you do within transaction scope is subject to race conditions.
So any SQL query you do to get the last used value, increment it, and store it in a new row means that two concurrent clients could fetch the same value and try to use it, resulting in a duplicate key.
There are a few solutions to this:
Locking. Each client sets an exclusive lock on the rows they read if you use
SELECT ... FOR UPDATE(as @Daniel Vassallo describes)Use auto-increment. This mechanism guarantees no race conditions, because allocation of new values happens without regard to transaction scope. As a benefit, no two concurrent clients will get the same value. This means, though, that a rollback doesn’t undo allocation of a value. The
LAST_INSERT_ID()function returns the last auto-increment value allocated by the current session, even if other concurrent clients are also generating values in the same table or different tables.Use an external solution. Generate primary key values not using SQL but with some other system in your application. You’re responsible for protecting against race conditions. For instance you could use a counting semaphore.
Use a pseudorandom, unique id. Primary keys need to be unique, but they don’t need to be monotonically increasing integers. Some people use the
UUID()function to generate a random 128-bit number that’s virtually guaranteed to not have duplicates. But then your primary keys have to use a larger data type such asCHAR(36)orBINARY(16)and it’s inconvenient to write ad hoc queries.SELECT * FROM MyTable WHERE id = ‘6ccd780c-baba-1026-9564-0040f4311e29’;
You mention in a comment that you “read some negative things” about using auto-increment. Of course any feature in any language has do’s and don’ts. It doesn’t mean we shouldn’t use those features — it means we should learn how to use them properly.
Can you describe your concerns or any of the negative things about auto-increment? Perhaps folks on this thread can address them.