MySQL INSERT .... ON DUPLICATE UPDATE - добавляет один к автоинкременту - PullRequest
13 голосов
/ 17 августа 2011

Я отслеживаю все http_user_agents, которые посещают меня, с помощью простого счетчика посещений. Ниже вставляется http_user_agent в БД, это поле не чувствительно к регистру и уникально. Поэтому, когда мы пытаемся вставить его и он находит ДУБЛИКАТНЫЙ КЛЮЧ, он добавляет 1 к полю хитов.

Проблема в том, что мое поле автоматического увеличения все еще увеличивается, хотя мы не вставляли поле. как я могу предотвратить это?

$sql = "INSERT INTO `db_agency_cloud`.`tblRefHttpUsersAgent` SET `http_users_agent` = :UsersAgent, `created_ts` = NOW() ON DUPLICATE KEY UPDATE `hits` = `hits` + 1";

Вот структура таблицы:

CREATE TABLE `tblRefHttpUsersAgent`
(
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`http_users_agent` varchar(255) NOT NULL,
`hits` int(20) unsigned NOT NULL DEFAULT '1',
`created_ts` datetime NOT NULL,
`activity_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `http_users_agent` (`http_users_agent`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

Ответы [ 3 ]

19 голосов
/ 18 августа 2011

INSERT ... ON DUPLICATE KEY UPDATE описывается как «вставка смешанного режима» для обработки AUTO_INCREMENT в InnoDB. Вставки в смешанном режиме - это, в основном, те, в которых максимальное количество требуемых AUTO_INCREMENT значений известно, но сумма, которая будет фактически необходима , не является.

Вставки в смешанном режиме обрабатываются специально по умолчанию, как описано в MySQL документах :

... для «вставок в смешанном режиме» ... InnoDB выделить больше значений автоинкремента, чем количество строк вставлено. Тем не менее, все значения автоматически присваиваются последовательно генерируется (и, следовательно, выше) значение автоинкремента самое последнее выполненное предыдущее утверждение. «Лишние» номера потерял.

Если вы используете InnoDB, ваши альтернативы:

  1. Избегайте INSERT ... ON DUPLICATE KEY UPDATE.
  2. Установите для параметра innodb_autoinc_lock_mode значение 0 для «традиционного» режима блокировки автоинкремента, который гарантирует, что все операторы INSERT будут назначать последовательные значения для столбцов AUTO_INCREMENT. Однако это достигается блокировкой во время оператора, поэтому с этим параметром связана потеря производительности.
  3. (рекомендуется) Игнорировать пробелы в столбце AUTO_INCREMENT.

Примечание: AUTO_INCREMENT обработка полностью отличается от MyISAM, который не демонстрирует это поведение.

5 голосов
/ 17 августа 2011

Механизм хранения должен увеличить значение AUTO_INCREMENT перед вставкой строки. Он не знает, произойдет ли вставка в этот момент. Он не может просто откатить приращение, потому что могут быть другие вставки, происходящие одновременно с другими соединениями. Это нормальное поведение, а не то, что вы должны (или можете) изменить. Цель AUTO_INCREMENT - предоставить уникальные идентификаторы, а не непрерывную последовательность чисел.

1 голос
/ 17 августа 2011

К сожалению, решение находится на уровне приложения, если вы не хотите влиять на идентификаторы автоинкремента. Сначала выполните SELECT и посчитайте строки результатов. Если 0 результатов, INSERT данные. Если больше 0, UPDATE эта строка.

...