Поля автоматичного збільшення MySQL скидає сам по собі


12

У нас є таблиця MySQL, у якій поле з автоматичним збільшенням встановлено як INT (11). Ця таблиця в значній мірі зберігає список завдань, які виконуються в додатку. У будь-який момент упродовж життя програми таблиця може містити тисячі записів або бути повністю порожньою (тобто все закінчилося).

Поле не є чужим для іншого.

Здається, автоматичний приріст здається випадковим чином скинутим до нуля, хоча ми ніколи насправді не змогли скинути скидання.

Проблема стає очевидною, оскільки ми бачимо, що поле з автоматичним збільшенням доходить, скажімо, до 600 000 записів або близько того, а потім деякий час поле для автоматичного збільшення збільшується в низьких 1000-х.

Це майже так, як якщо автоматичне збільшення збільшується, якщо таблиця порожня.

Чи можливо це, і якщо це так, як я його відключую чи змінюю спосіб його скидання?

Якщо це не так, чи має хтось пояснення, чому це може робити?

Дякую!


Яка версія MySQL? Чи використовуються транзакції чи тиражування?
thinice

Відповіді:


26

Лічильник автоматичного збільшення лише зберігається в основній пам'яті, а не на диску.

http://dev.mysql.com/doc/refman/4.1/uk/innodb-auto-increment-handling.html

Через це, коли служба (або сервер) перезапуститься, станеться таке:

Після запуску сервера, для першої вставки в таблицю t, InnoDB виконує еквівалент цього оператора: SELECT MAX (ai_col) ВІД t ЗА ОНОВЛЕННЯ;

Збільшення InnoDB на одне значення, отримане в операторі і призначає його стовпцю та лічильнику автоматичного збільшення для таблиці. Якщо таблиця порожня, InnoDB використовує значення 1.

Отже, простою англійською мовою після запуску служби MySQL вона не має уявлення про те, яким має бути значення автоматичного збільшення вашої таблиці. Отже, коли ви вперше вставляєте рядок, воно знаходить максимальне значення поля, яке використовує автоматичне збільшення, додає 1 до цього значення та використовує отримане значення. Якщо рядків немає, він розпочнеться з 1.

Це було для нас проблемою, оскільки ми використовували функцію таблиці та автоматичного збільшення функції mysql, щоб акуратно керувати ідентифікаторами у багатопотоковому середовищі, де користувачі перенаправлялися на сторонній веб-сайт оплати. Таким чином, ми повинні були переконатися, що ідентифікатор, який отримала третя сторона та повернув нам назад, був унікальним і залишився таким (і, звичайно, є можливість, щоб користувач скасував транзакцію після того, як був перенаправлений).

Таким чином, ми створювали рядок, отримували згенероване значення автоматичного збільшення, видаляли рядок для збереження чистоти таблиці та пересилали значення на сайт оплати. Ми вирішили вирішити питання про те, як InnoDB обробляє значення AI:

$query = "INSERT INTO transactions_counter () VALUES ();";
mysql_query($query);
$transactionId = mysql_insert_id();
$previousId = $transactionId - 1;
$query = "DELETE FROM transactions_counter WHERE transactionId='$previousId';";
mysql_query($query); 

Це завжди зберігає останню згенеровану ID транзакції у вигляді рядка в таблиці, без зайвого підриву таблиці.

Сподіваємось, що це допоможе комусь, хто може зіткнутися з цим.

Редагувати (2018-04-18) :

Як зазначено нижче Finesse, схоже, поведінка цього варіанту була змінена в MySQL 8.0+.

https://dev.mysql.com/worklog/task/?id=6204

Формулювання в цьому робочому журналі в кращому випадку є несправним, проте, як видається, InnoDB у тих новіших версіях тепер підтримує стійкі значення автоінциклу через перезавантаження.

-Греміо


Непогано для першого поста, чувак. +1.
ceejayoz

Солодкий шматочок знань там Греміо. Дякую!! Я повністю відклав це і заархівував проблему всередині як щось, що потрібно переглянути згодом, але повернувшись до нього, ваше рішення викликає привабливість!
Хуліганкат

3

Ми випробували цю проблему і виявили, що коли оптимізувати таблицю було запущено на порожній таблиці, значення автоматичного збільшення також було скинуто. Дивіться цей звіт про помилки MySQL .

Як вирішення, ви можете:

ALTER TABLE a AUTO_INCREMENT=3 ENGINE=innoDB;

Замість цього OPTIMIZE TABLE.

Здається, це те, що MySQL робить всередині (очевидно, не встановлюючи значення автоматичного збільшення)


2

Лише знімок у темряві - якщо програма використовує a TRUNCATE TABLEдля очищення таблиці під час обробки, це скине поле автоматичного збільшення. Ось коротке обговорення цього питання. Хоча ця посилання зазначає, що InnoDB не скидає auto_increments на магістраль, про це повідомлялося як про помилку та виправлено кілька років тому.

Якщо припустити, що ви гадаєте, ви можете перейти від обрізання до видалення, щоб вирішити проблему.


Я не думав, що ми використовуємо TRUNCATE, але нам потрібно було перевірити, щоб переконатися. Навіть зайшов так далеко, щоб перевірити до рівня драйвера PHP, щоб переконатися. Але ми не були. Хоча оцініть можливе рішення.
Хуліганкат

1

Лише явне скидання цього значення, або падіння / відтворення цього поля, або інші подібні насильницькі операції повинні коли-небудь скинути лічильник автоматичного збільшення. (TRUNCATE була дійсно хорошою теорією.) Здається, неможливо, ви раптом загортаєте 32-бітний INT, коли останнє значення, якому ви є свідком, становить лише 600k. Він, безумовно, не повинен скидатися лише тому, що таблиця спорожняється. У вас є помилка mysql або щось у вашому PHP-коді. Або хлопець у сусідній кабінці грає на вас трюк.

Ви можете налагоджувати помилку, увімкнувши двійковий журнал , оскільки він буде містити такі оператори протягом усього:

SET INSERT_ID=3747670/*!*/;

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


дякую за пораду налагодження. Минув час, як мені потрібно було перевірити сервер за замовчуванням, і я ціную вашу пораду
Hooligancat

0

ALTER TABLE table_name ENGINE = MyISAM

Працює для мене. Наш стіл завжди зберігається дуже мало, тому немає необхідності в InnoDB.


Вам потрібні транзакції?
Ентоні Ратлідж

0

InnoDB не зберігає значення автоматичного збільшення на диску, тому він забуває його при відключенні сервера MySQL. Коли MySQL запускається знову, двигун InnoDB відновлює значення автоматичне збільшення в такий спосіб: SELECT (MAX(id) + 1) AS auto_increment FROM table. Це помилка, яка виправлена у MySQL версії 8.0.

Змініть двигун таблиці, щоб вирішити проблему:

ALTER TABLE table ENGINE = MyISAM

Або оновіть сервер MySQL до версії 8.0 після його виходу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.