MySQL - автоинкремент не увеличивается последовательно, если последняя строка была удалена

8

У меня есть таблица, которая содержит автоматически увеличенный идентификатор первичного ключа. Если я удаляю последнюю строку (самый высокий идентификатор, например, для экспертизы = 6) и вставляю новую строку, новый идентификатор начинается с 7. Какой параметр мне нужно изменить, чтобы первичный ключ начинался с 6?

CREATE TABLE animals (
 id MEDIUMINT NOT NULL AUTO_INCREMENT,
 name CHAR(30) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=MyISAM;

INSERT INTO animals (name) VALUES
('dog'),('cat'),('penguin'),
('lax'),('whale'),('ostrich');

Результат:
имя
1 собака
2 кошка
3 пингвин
4 слабый
5 кит
6 страус

DELETE FROM animals WHERE id = 6;
INSERT INTO animals (name) VALUES
('x');

Результат:
имя
1 собака
2 кошка
3 пингвин
4 слабый
5 кит
7 х

Спасибо за совет.

Джордано
источник
Так что, если есть пробелы? (который может появиться по нескольким другим причинам, а не только путем удаления строк)
ypercubeᵀᴹ
что бы вы хотели сделать, если удаление произойдет после некоторой вставки? ты собираешься использовать этот пробел? да, тогда я не думаю, что идентичность является правильным типом для этого столбца. это дает вам возможность не беспокоиться об уникальных значениях в этом столбце. если вы намереваетесь хранить значения в последовательности, то можете просто использовать обычный тип данных типа INT / BIGINT. Нахождение / повторное использование / сброс значений для каждого пропущенного пробела похоже на утрату цели Identity Property.
Ануп Шах
@giordano Почему вы хотите быть аккуратным фанатом AUTO_INCREMENT PRIMARY? В случае, если вы обновляете / удаляете из-за фрагментации, в данных вашей таблицы также есть «пробел».
Раймонд Нейланд
Некоторое время назад я провел расследование по поводу непрерывных значений auto_increment для SQL Server: sqlity.net/en/792/the-gap-in-the-identity-value-sequence - Хотя это не для MySQL, базовые механизмы одинаковы , так что вы получите аналогичные результаты. Короче говоря, вы не можете предотвратить разрывы автоматически сгенерированных последовательностей.
Себастьян Майн,
@ypercube: спасибо за ответы. Действительно, пробел я получил от другого более сложного примера, но я хотел показать минимальный пример. Реальным примером было (1) изменение даты истечения срока действия строки (например, из таблицы продуктов) из-за изменения атрибута и (2) добавление нового продукта с тем же кодом продукта, новым атрибутом, новой датой вступления в силу и открытым сроком действия свидание. Что произошло, так это то, что новый первичный ключ не увеличивался автоматически с +1, но +2. Очевидно, что на этапе (1) или (2) происходит невидимое автоматическое приращение. Интересно, каковы другие причины пробелов.
Джордано

Ответы:

12

Это по замыслу - все СУБД действуют так, как это было с автоинкрементными столбцами.

В противном случае внешняя ссылочная целостность может быть повреждена. Для простого примера представьте, что вы храните URL-адреса сокращающей службы, используя в качестве ключа столбец с автоинкрементом. Вы не знаете, был ли кому-либо выдан сокращенный URL, а база данных, конечно же, нет, поэтому повторное использование идентификатора 1234 может привести к тому, что чья-то бедная бабушка посетит somenastypornsite.xxx вместо loverlyknitting.org, когда она щелкает http: / /shortthi.ng/1234 в старом письме, вместо того, чтобы получить сообщение «извините, но эта ссылка больше не существует в наших записях».

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

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

Как правило, я рекомендую людям, работающим с базами данных, прочитать «Антипаттерны SQL», в которых есть глава по этому вопросу, озаглавленная «Аккуратные уловки с псевдо-ключами» (которая охватывает этот вопрос более дружественным образом, чем заголовок главы может показывать некоторым!). По сути, если значение имеет значение помимо того, что оно является ключом (или, самое большее, содержит информацию о порядке вставки), то, вероятно, оно не должно быть столбцом с автоинкрементным увеличением, и если оно не имеет значения, кроме того, что оно является ключом (или, в большинстве случаев, имеет порядок вставки). информация) тогда пробелы не должны иметь значения.

Дэвид Спиллетт
источник
Спасибо за это объяснение. Я вижу, что мне нужно углубиться в ключевую концепцию. Интересно, как работает механизм автоматического приращения, поскольку я наблюдал также пробелы в первичном ключе, когда я не удалял его, а изменял (обновлял) одну строку и добавлял новую. Определенно, что я не буду делать, так это изменять значение автоматического приращения вручную.
Джордано
Что касается «углубиться в концепцию ключа», я настоятельно рекомендую книгу Билла Карвина «Антипаттерны SQL» - в ней освещается эта и ряд других общих (и не очень) тем, рассказывающих о том, как ошибиться, почему распространено неправильно методы могут вызывать проблемы, как их исправлять, и когда «неправильный» метод может быть приемлем для использования (или единственного выбора) в любом случае, кратким, но доступным способом.
Дэвид Спиллетт
Спиллет: Спасибо за это указание. Я читаю сейчас, и это было очень полезно. Тем не менее, я не понимаю, почему InnoDB и MyISAM считают по-разному: dba.stackexchange.com/questions/51883/…
giordano
0

Вы можете сбросить значение auto_increment, используя следующее:

ALTER TABLE MyTable AUTO_INCREMENT = 1234;

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

Макс Вернон
источник
Плохая идея, это заблокирует вашу таблицу от чтения или записи в «почти всех» версиях MySQL. MySQL 5.6 может сделать LIVE ALTER, но иногда это также необходимо для блокировки таблицы.
Рэймонд Нейланд
2
@RaymondNijland Я не думаю, что замок будет длиться достаточно долго, чтобы кто-нибудь мог заметить.
ypercubeᵀᴹ
@ Макс, Раймонд, ypercube: Спасибо за ответ. Я избегу делать такие изменения.
Джордано