Комментарии: Неявная проблема ON DUPLICATE KEY и AUTO INCREMENT https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/ Случаи из опыта разработки различных WEB проектов. Интересные факты, статьи, впечатления. Программирование и все о нем в сфере WEB. Wed, 24 Jul 2024 13:00:31 +0000 hourly 1 https://wordpress.org/?v=6.9.1 Автор: max https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-72322 Wed, 24 Jul 2024 13:00:31 +0000 http://intsystem.org/?p=825#comment-72322 В ответ на kivagant.

Тогда делайте так:

ALTER TABLE table_name AUTO_INCREMENT = 1;

Если AUTO_INCREMENT <= MAX(`id`), то будет AUTO_INCREMENT = MAX(`id`) + 1

]]>
Автор: Сергей https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-61327 Sun, 05 Feb 2023 10:06:55 +0000 http://intsystem.org/?p=825#comment-61327 Это объясняется особенностями построковй блокировки таблиц InnoDB и сделано для ускорения работы.

Поведение становится немного лучше если в my.cnf добавить строку
innodb_autoinc_lock_mode=0

автоинкремент все равно не последовательный, но растет не так быстро.
Кстати, такая же проблема если используются INSERT IGNORE
если вставки игнорируются, то счетчик все равно прирастает

Самое кардинальное, для таких таблиц использовать не InnoDB а MyISAM

]]>
Автор: Serg https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-31758 Sat, 31 Mar 2018 11:21:50 +0000 http://intsystem.org/?p=825#comment-31758 В ответ на kivagant.

Никто никого не обманывает, проблема на самом деле очень серьёзная существует.
После 10 неудачных по UNIQUE постов в таблицу, действительно при запросе
SELECT * FROM `test_table`\G
будет id: 1
НО! при следующем удачном посте id=11.
В этом офигезная проблема!

]]>
Автор: Дмитрий Амиров https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-26015 Sun, 18 Dec 2016 17:16:00 +0000 http://intsystem.org/?p=825#comment-26015 В ответ на Иван.

Тем что в случае с REPLACE

старая запись перед занесением новой будет удалена

По сути в таком случае вместо апдейта, выполнится два действия — delete и insert. Это более накладно.

]]>
Автор: Иван https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-26005 Sun, 18 Dec 2016 07:46:41 +0000 http://intsystem.org/?p=825#comment-26005 Я конечно может не по теме.
А что мешает делать REPLACE

]]>
Автор: kivagant https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-23037 Fri, 25 Dec 2015 11:13:58 +0000 http://intsystem.org/?p=825#comment-23037 В ответ на Дмитрий Амиров.

Конечно, рекомендовать перезапускать сервис после каждого insert было бы смешно.

А в целом да, получается что ON DUPLICATE KEY UPDATE для реализации счётчиков и статистики на высоких нагрузках может давать неожиданный результат и больше подходит для каких-то более тривиальных манипуляций состоянием сущностей в базе.

]]>
Автор: Дмитрий Амиров https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-23036 Fri, 25 Dec 2015 08:45:47 +0000 http://intsystem.org/?p=825#comment-23036 В ответ на kivagant.

Хм, честно сказать, никогда не задумывался об этом.

В принципе в этом нет ничего удивительного, насколько я помню, в InnoDB счетчик AUTO_INCREMENT хранится в памяти, а не где то физически, и логично что после перезапуска сервера он инициализируется заново.

PS: я немного вспылил, сорри

UPD: да, хранится в памяти, и инициализируется после перезапуска см. тут:

This counter is stored only in main memory, not on disk.

To initialize an auto-increment counter after a server restart, InnoDB executes the equivalent of the following statement on the first insert into a table containing an AUTO_INCREMENT column.

SELECT MAX(ai_col) FROM table_name FOR UPDATE;

]]>
Автор: kivagant https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-23035 Fri, 25 Dec 2015 08:13:32 +0000 http://intsystem.org/?p=825#comment-23035 В ответ на Дмитрий Амиров.

Надеюсь вы не поленитесь зайти и принести свои извинения

Не поленюсь, я всегда признаю если не прав и тем более рад узнать что-то новое. Приношу свои извинения.

Так вот, во-первых да, автоинкремент приростает для следующей записи.

Но вот вам ещё сюрприз, о котором вы, возможно, тоже не знали:
1.
INSERT INTO `test_table` (`date`, `value`) VALUES (‘2015-12-31’, 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;
(несколько одинаковых вставок подряд)

2.
show create table test_table;
… ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8

3. service mysql restart

4.
show create table test_table;
… ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8

Автоинкремент пересчитался до значения последней строки плюс одна запись:

select * from test_table

|  1 | 2015-12-24 |     5 |
|  2 | 2015-12-25 |     8 |
| 10 | 2015-12-26 |     5 |
| 15 | 2015-12-27 |     3 |
| 18 | 2015-12-28 |     1 |
| 19 | 2015-12-29 |     2 |
| 21 | 2015-12-30 |     4 |
| 22 | 2015-12-31 |    10 |
]]>
Автор: Дмитрий Амиров https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-23030 Fri, 25 Dec 2015 05:30:08 +0000 http://intsystem.org/?p=825#comment-23030 В ответ на kivagant.

Тестируйте свои примеры прежде чем всякую чепуху публиковать.

Статью внимательнее читайте, прежде чем всякую чепуху в комментариях писать.

После ваших запросов, делаем (допустим наступил следующий день):

INSERT INTO `test_table` (`date`, `value`) VALUES ('2015-12-25', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;

И смотрим в таблицу:

+----+------------+-------+
| id | date       | value |
+----+------------+-------+
|  1 | 2015-12-24 |     5 |
|  6 | 2015-12-25 |     1 |
+----+------------+-------+

Проблема, описанная в статье, видна наглядно. А именно — ID второй записи равен шести, а не двум, как это должно было бы быть, если рассуждать логически.

]]>
Автор: kivagant https://intsystem.org/sql/neyavnaya-problema-on-duplicate-key-i-auto-incriment/#comment-23027 Thu, 24 Dec 2015 17:35:37 +0000 http://intsystem.org/?p=825#comment-23027

Допустим это некий скрипт счетчик посещений за день. Суть в том что любое выполнение этого запроса, вне зависимости от того был INSERT или UPDATE, приводит к увеличению счетчика AUTO INCRIMENT (справедливо только для InnoDB). Что это значит?

Зачем людей обманываете?

CREATE TABLE `test_table` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`date` DATE NOT NULL ,
`value` INT UNSIGNED NOT NULL ,
PRIMARY KEY ( `id` ) ,
UNIQUE ( `date` )
) ENGINE = INNODB ;
-- Query OK, 0 rows affected (0.07 sec)

INSERT INTO `test_table` (`date`, `value`) VALUES ('2015-12-24', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;
-- Query OK, 1 row affected (0.00 sec)
-- SELECT * FROM `test_table`\G
--    id: 1
--  date: 2015-12-24
-- value: 1
-- 1 row in set (0.00 sec)

INSERT INTO `test_table` (`date`, `value`) VALUES ('2015-12-24', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;
-- Query OK, 2 rows affected (0.00 sec)

INSERT INTO `test_table` (`date`, `value`) VALUES ('2015-12-24', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;
-- Query OK, 2 rows affected (0.00 sec)

INSERT INTO `test_table` (`date`, `value`) VALUES ('2015-12-24', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;
-- Query OK, 2 rows affected (0.00 sec)

INSERT INTO `test_table` (`date`, `value`) VALUES ('2015-12-24', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1;
-- Query OK, 2 rows affected (0.00 sec)

SELECT * FROM `test_table`\G
--    id: 1
--  date: 2015-12-24
-- value: 5
-- 1 row in set (0.00 sec)

Тестируйте свои примеры прежде чем всякую чепуху публиковать.

]]>