Почему массовые вставки INNODB заставляют первичный ключ с автоинкрементом пропускать значения? - PullRequest
3 голосов
/ 24 января 2012

Мне знаком тот факт, что неудачные вставки в InnoDB приводят к пробелам в автоинкрементном первичном ключе, я считаю, что это не связано (это не очевидно для меня).Проблема, с которой я сталкиваюсь, заключается в том, что я вставлю 5 записей в таблицу с автоматически увеличенным первичным ключом, в результате чего первичный ключ будет иметь разрыв от 5 до 8. Вот сценарий для повторения проблемы.

DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
`A` int(10) unsigned NOT NULL AUTO_INCREMENT,
`B` int(10) unsigned NOT NULL,
PRIMARY KEY (`A`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

insert into `test_table` (`B`)
SELECT 1
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5;

insert into `test_table` (`B`)
SELECT 6
UNION
SELECT 7
UNION
SELECT 8
UNION
SELECT 9
UNION
SELECT 10;

SELECT * FROM `test_table`;

Я ожидаю, что в этом случае оба столбца A и B будут одинаковыми, но в начале второй вставки A будет 8, а B - 6. Кто-нибудь знает, почему возникает этот пробел?

Я посмотрел документацию здесь: http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html но эти режимы блокировки, похоже, не связаны с этим пробелом (я мог что-то упустить).

Ответы [ 2 ]

4 голосов
/ 24 января 2012

По какой-то причине 'INSERT INTO test_table (B) SELECT 1 UNION SELECT 2' устанавливает AUTO_INCREMENT = 4, но эта вставка работает как положено -

INSERT INTO `test_table` (`B`)
VALUES (1), (2), (3), (4), (5);

INSERT INTO `test_table` (`B`)
VALUES (6), (7), (8), (9), (10);

Попробуйте установить innodb_autoinc_lock_mode = 0 и снова запустить скрипт, пробелов не будет.

AUTO_INCREMENT Обработка в InnoDB .

1 голос
/ 24 января 2012

Я думаю, что к анализатору запросов была предложена приблизительная оценка того, сколько строк будет возвращено внутренним запросом, и он был слегка отключен.

Механизм базы данных должен стремиться к трем противоречивым целям:

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

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

Это гарантирует, что одновременный INSERT будет иметь меньшую или большую первичную kзначения ey (т. е. запросы правильно сериализованы), но данные могут быть добавлены между строками (поскольку упорядочение отсутствует, если вы не используете предложение ORDER BY)

...