Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emulating a transaction-safe SEQUENCE in MySQL

We're using MySQL with InnoDB storage engine and transactions a lot, and we've run into a problem: we need a nice way to emulate Oracle's SEQUENCEs in MySQL. The requirements are: - concurrency support - transaction safety - max performance (meaning minimizing locks and deadlocks)

We don't care if some of the values won't be used, i.e. gaps in sequence are ok. There is an easy way to archieve that by creating a separate InnoDB table with a counter, however this means it will take part in transaction and will introduce locks and waiting. I am thinking to try a MyISAM table with manual locks, any other ideas or best practices?

like image 373
Michael Pliskin Avatar asked Apr 30 '09 07:04

Michael Pliskin


People also ask

How do I execute a sequence in MySQL?

Create a table to hold the sequence counter and initialize it: mysql> CREATE TABLE sequence (id INT NOT NULL); mysql> INSERT INTO sequence VALUES (0); Use the table to generate sequence numbers like this: mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1); mysql> SELECT LAST_INSERT_ID();

Does MySQL transaction lock table?

MySQL Locks: Write LocksIt is the session that holds the lock of a table and can read and write data both from the table. It is the only session that accesses the table by holding a lock. And all other sessions cannot access the data of the table until the WRITE lock is released.

How does MySQL transactions work?

In MySQL, the transactions begin with the statement BEGIN WORK and end with either a COMMIT or a ROLLBACK statement. The SQL commands between the beginning and ending statements form the bulk of the transaction.


1 Answers

If auto-increment isn't good enough for your needs, you can create a atomic sequence mechanism with n named sequences like this:

Create a table to store your sequences:

CREATE TABLE sequence (
  seq_name varchar(20) unique not null,
  seq_current unsigned int not null
);

Assuming you have a row for 'foo' in the table you can atomically get the next sequence id like this:

UPDATE sequence SET seq_current = (@next := seq_current + 1) WHERE seq_name = 'foo';
SELECT @next;

No locks required. Both statements need to be executed in the same session, so that the local variable @next is actually defined when the select happens.

like image 123
Arne Claassen Avatar answered Sep 27 '22 16:09

Arne Claassen