2016-07-13 2 views
3

У меня возникают проблемы с первичным ключом ID, который установлен в auto increment. Он продолжает увеличиваться ON DUPLICATE KEY.Предотвращение автоматического приращения InnoDB ON DUPLICATE KEY

Для примера:

ID | field1  | field2 

1 | user  | value 

5 | secondUser | value 

86 | thirdUser | value 

Из приведенного выше описания, вы увидите, что у меня есть 3 входа в этой таблице, но из-за автоматическое приращение на каждое обновлении, ID имеет 86 для третьего входа.

Есть ли вообще избежать этого?

Вот что мой запрос MySQL выглядит следующим образом:

INSERT INTO table (field1, field2) VALUES (:value1, :value2) 
      ON DUPLICATE KEY 
      UPDATE field1 = :value1, field2 = :value2 

И вот что моя таблица выглядит;

CREATE TABLE IF NOT EXISTS `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `field1` varchar(200) NOT NULL, 
    `field2` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `field1` (`field1`), 
    KEY `id` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 
+1

Он никогда не должен быть критическим, чтобы иметь последовательные идентификаторы, только уникальные ....если вам нужен последовательный, то что-то не так с вашим дизайном –

+0

@MarkBaker Я отредактировал сообщение, чтобы включить мою структуру дизайна таблицы. – youngbobby

+1

Сделайте еще один столбец в таблице, где вы можете вручную добавить целое число, а затем вы можете сохранить этот столбец последовательным, например столбец 'sID', а затем вы можете найти значение MAX, а затем +1 для этого значения для вашей последней вставки. (возможно, вы можете автоматически сделать это в SQL-запросе) – Martin

ответ

3

Вы можете установить опцию innodb_autoinc_lock_mode конфигурации в "0" для «традиционного» режима блокировки автоинкрементной, что гарантирует, что все INSERT заявление будет назначать последовательные значения для AUTO_INCREMENT столбцов.

Таким образом, вы не должны зависеть от того, что идентификаторы автоматического инкремента являются последовательными в вашем приложении. Их цель - предоставить уникальные идентификаторы.

+0

Спасибо за ссылку. Я не знал, что это вариант – BeetleJuice

+0

Я нахожусь на общем хостинге :( – youngbobby

1

я в настоящее время возникают проблемы с первичным ключом ID, который установлен на auto increment. Он продолжает увеличиваться ON DUPLICATE KEY

Один из нас, должно быть, неправильно понимает проблему, или вы неверно представляете ее. ON DUPLICATE KEY UPDATE никогда не создает новую строку, поэтому она не может увеличиваться. От the docs:

Если вы указываете ON KEY UPDATE DUPLICATE, и вставляется строка, что может вызвать повторяющееся значение в уникальный индекс или первичный ключ, MySQL выполняет UPDATE старой строки.

Теперь это, наверное, тот случай, когда автоматическое увеличение происходит при вставке и не дубликата ключа не найден. Если я предполагаю, что это то, что происходит, мой вопрос будет: почему это проблема?

Если вы абсолютно хотите контролировать значение вашего первичного ключа, измените структуру таблицы, чтобы удалить флаг auto-increment, но сохраните это обязательное, ненулевое поле. Это заставит вас предоставить ключи самостоятельно, но я бы поспорил, что это станет для вас большей головной болью.

Мне действительно любопытно: зачем вам подключать все отверстия в значениях ID?

+0

Я отредактировал мое сообщение, чтобы включить структуру таблицы – youngbobby

+1

Вы не можете подключить отверстия в реальной системе. Потому что в какой-то момент вы удаляете строку. И вы не можете переместить все ПК и FK во все дочерние таблицы (или, по крайней мере, один из идентификаторов в качестве горячей замены в новое отверстие). Не может означать, что он еще не может оставаться в здравом уме. Поэтому люди без ОКР просто уходят достаточно хорошо. – Drew

1

Это поведение легко увидеть ниже с установкой по умолчанию для innodb_autoinc_lock_mode = 1 («последовательный» режим блокировки). Просьба также указать прекрасную справочную страницу под названием AUTO_INCREMENT Handling in InnoDB. Изменение этого значения уменьшит параллелизм и производительность с установкой = 0 для режима блокировки «Tranditional», поскольку он использует блокировку AUTO-INC на уровне таблицы.

Тем не менее, ниже с настройками по умолчанию = 1.

я собираюсь показать вам четыре примеры того, как легко создать пробелы.

Пример 1:

create table x 
( id int auto_increment primary key, 
    someOtherUniqueKey varchar(50) not null, 
    touched int not null, 
    unique key(someOtherUniqueKey) 
); 
insert x(touched,someOtherUniqueKey) values (1,'dog') on duplicate key update touched=touched+1; 
insert x(touched,someOtherUniqueKey) values (1,'dog') on duplicate key update touched=touched+1; 
insert x(touched,someOtherUniqueKey) values (1,'cat') on duplicate key update touched=touched+1; 

select * from x; 
+----+--------------------+---------+ 
| id | someOtherUniqueKey | touched | 
+----+--------------------+---------+ 
| 1 | dog    |  2 | 
| 3 | cat    |  1 | 
+----+--------------------+---------+ 

Разрыв (ID = 2 пропускается) происходит из-за одной из нескольких операций и причудами и нервных подергиваний в INNODB двигателя. В стандартном высокопроизводительном режиме параллелизма он выполняет распределение интервалов пробелов для различных запросов, отправленных ему. У кого-то есть хорошие причины изменить эту настройку, потому что это влияет на производительность. Похоже на то, что более поздние версии MySQL доставляют вам, и вы отключились из-за Hyper Focusing на пробелы в листах распечаток (и боссы, которые говорят «Почему у нас есть пробелы»).

В случае вставки в обновлении повторяющейся клавиши (IODKU) он принимает 1 новую строку и выделяет для нее слот. Помните, что параллелизм и ваши сверстники выполняют одни и те же операции, возможно, сотни одновременно. Когда IODKU превращается в Update, ну, используется использование этой заброшенной и никогда не вставленной строки с id = 2 для вашего подключения и любого другого.

Пример 2:

То же самое происходит во время Insert ... Select From, как видно на This Answer шахты. В нем я намеренно использую MyISAM из-за сообщения о подсчетах, min, max, в противном случае отклонение диапазона пробелов будет выделять и не заполнять все. И цифры выглядели бы странно, поскольку этот ответ касался фактических чисел. Таким образом, более старый двигатель (MyISAM) отлично справился с трудными не-зазорами. Обратите внимание, что в этом ответе я пытался сделать что-то быстро и безопасно, и таблица могла быть преобразована в INNODB с ALTER TABLE после факта. Если бы я сделал этот пример в INNODB для начала, было бы много пробелов (в режиме по умолчанию). Причина, по которой имела бы, создает пробелы в этом ответе, если я использовал INNODB, был связан с неопределенностью счетчика, механизмом, который движок выбирает для безопасного (неопределенного) распределения диапазона. Двигатель INNODB знает операцию, естественно, знает, что должен создать безопасный пул AUTO_INCREMENT id, имеет параллелизм (другие пользователи думают), а пробелы процветают. Это факт. Попробуйте пример 2 с двигателем INNODB и посмотрите, что вы придумали для min, max и count. Макс не будет равным счетчику.

Примеры 3 и 4:

Существуют различные ситуации, которые вызывают INNODB Пробелы документированные на сайте Percona, как они натыкаются на более и документировать их. Например, это происходит во время неудачных вставок из-за ограничений внешнего ключа, наблюдаемых в этом 1452 Error image. Или ошибка основного ключа в этом 1062 Error image.

Помните, что промежутки INNODB являются побочным эффектом производительности системы и безопасного двигателя. Это что-то действительно хочет отключить (производительность, более высокая степень удовлетворенности пользователей, более высокий параллелизм, отсутствие блокировок в сети), ради более жестких диапазонов идентификаторов? Диапазоны, в которых есть дыры при удалении. Я бы предложил не для моих реализаций, а значение по умолчанию с Performance просто отлично.

Смежные вопросы