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

StackOverflow https://stackoverflow.com/questions/805808

  •  03-07-2019
  •  | 
  •  

Вопрос

Мы часто используем MySQL с механизмом хранения и транзакциями InnoDB и столкнулись с проблемой:нам нужен хороший способ эмулировать ПОСЛЕДОВАТЕЛЬНОСТИ Oracle в MySQL.Требования:- Поддержка параллелизма - Безопасность транзакций - максимальная производительность (что означает минимизация замков и тупиков)

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

Это было полезно?

Решение

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

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

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 фактически определялась, когда происходит выбор.

Другие советы

Как это сделать, описано в Руководство по MySQL:

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

Мы являемся игровой компанией с высоким уровнем транзакций, и нам нужны такого рода решения для наших нужд.Одной из особенностей последовательностей 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";

Разве столбец MySQL Identity в таблице не справится с этим?

Create Table Table_Name (ID Integer Auto_Increment Первичный ключ)

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

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

(Примечание: всегда увеличивайте значение перед возвратом значения — это максимизирует вероятность отсутствия дубликатов в случае ошибок — или оберните все это в транзакцию.)

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top