Эмуляция безопасной транзакции SEQUENCE в MySQL

Мы много используем MySQL с механизмом хранения и транзакциями InnoDB, и у нас возникла проблема: нам нужен хороший способ эмуляции Oracle SEQUENCE в MySQL. Требования:  - поддержка concurrency  - безопасность транзакций  - максимальная производительность (что означает минимизацию блокировок и взаимоблокировок)

Нам все равно, если некоторые из значений не будут использоваться, т.е. пробелы в порядке. Существует простой способ архивирования, создавая отдельную таблицу InnoDB со счетчиком, однако это означает, что он примет участие в транзакции и будет вводить блокировки и ждать. Я собираюсь попробовать таблицу MyISAM с ручными замками, любыми другими идеями или передовыми методами?

Ответ 1

Если автоинкремент недостаточно хорош для ваших нужд, вы можете создать механизм атомной последовательности с n именованными последовательностями, например:

Создайте таблицу для хранения ваших последовательностей:

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

Предполагая, что у вас есть строка для 'foo' в таблице, вы можете атомарно получить следующий идентификатор последовательности следующим образом:

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

Никаких блокировок не требуется. Оба оператора должны выполняться в том же сеансе, так что локальная переменная @next фактически определяется при выборе select.

Ответ 2

Правильный способ сделать это указан в руководстве MySQL:

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();

Ответ 3

Мы являемся компанией с высокими транзакционными играми и нуждаемся в таких решениях для наших нужд. Одной из особенностей последовательностей Oracle было также значение приращения, которое также можно было установить.

В решении используется DUPLICATE KEY.

CREATE TABLE sequences (
  id BIGINT DEFAULT 1,
  name CHAR(20),
  increment TINYINT,
  UNIQUE KEY(name)
);

Чтобы получить следующий индекс:

Опишите следующее с помощью хранимой процедуры или функции sp_seq_next_val(VARCHAR):

INSERT INTO sequences (name) VALUES ("user_id") ON DUPLICATE KEY UPDATE id = id + increment;<br/>
SELECT id FROM sequences WHERE name = "user_id";

Ответ 4

Не будет ли столбец идентификатора MySQL в таблице?

CREATE TABLE имя_таблицы (  id INTEGER AUTO_INCREMENT ПЕРВИЧНЫЙ КЛЮЧ )

Или вы хотите использовать его для чего-то другого, кроме как вставки в другую таблицу?

Если вы пишете, используя также процедурный язык (вместо простого SQL), то другой вариант должен состоять в создании таблицы, содержащей одно целое (или длинное целое) значение и хранимую процедуру, которая блокировала его, выбранную из он, увеличил его и разблокировал, прежде чем возвращать значение.

(Примечание. Всегда возвращайте значение до того, как вы вернете значение. Это максимизирует вероятность того, что вы не получите дубликатов, если есть ошибки, или оберните все это в транзакции.)

Затем вы вызывали бы это независимо от основной вставки/обновления (чтобы он не попадал в какие-либо транзакции, автоматически созданные механизмом вызова), а затем передавайте его как параметр в любом месте, где вы хотите его использовать.

Поскольку он не зависит от остальной части материала, который вы делаете, он должен быть быстрым и избегать проблем с блокировкой. Даже если вы видели ошибку, вызванную блокировкой (маловероятно, если вы не перегружаете базу данных), вы можете просто называть ее вторым/третьим временем.