Попередження скидання ідентифікатора auto_increment в базі даних Innodb після перезавантаження сервера


11

Нещодавно я прочитав, що через те, як InnoDB перераховує значення AUTO_INCREMENT при перезапуску сервера, будь-які записи у верхньому кінці списку ідентифікаторів можуть повторно використовувати свої ідентифікатори.

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

Але я навмисно залишаю їхні форуми осиротіли, позначені як "Опубліковано = Користувач # 123 =", щоб минулі розмови зберігалися. Зрозуміло, що якщо повторно використовувати ідентифікатор, це буде проблемою.

У мене ніколи не виникало цієї проблеми, тому що завжди було достатньо нових користувачів, щоб зробити її ідентифікатором малоймовірним повторно використовувати таким чином. Однак у моєму новому підписці на проект трапляються рідкісні та неактивні видалення користувачів (тим більше, що облікові записи "Відкритої Альфи" тривають лише три дні як попередній перегляд), і повторне повторне використання ідентифікатора вже три за три.

Я "виправив" проблему, зберігаючи правильне значення для AUTO_INCREMENT в іншому місці та використовуючи це, а не покладаючись на внутрішнє значення. Чи існує фактичний спосіб запам'ятати InnoDB фактичне останнє значення?


Чи є у вас прочитана стаття?
gbn

@gbn Посилання на статтю dev.mysql.com/doc/refman/5.1/uk/…
Naveen Kumar

Для довідки це bugs.mysql.com/bug.php?id=199
Laurynas Biveinis

ALTER TABLE table_name ENGINE = MyISAM працює для мене. Наш стіл завжди зберігається дуже мало, тому немає необхідності в InnoDB.

1
@QuickFix Ви повинні додати детальну інформацію про те, чому це працює.
Макс Вернон

Відповіді:


5

(уникаючи проблеми, ніколи не видаляючи)

Оскільки ви хочете зберегти "Posted by =User #123="інформацію після видалення користувача id=123, ви можете також розглянути можливість використання двох таблиць для зберігання даних користувачів. Один для Activeкористувачів і один для всіх (включаючи видалені з активних користувачів). І ніколи не видаляйте ці ідентифікатори зі AllUserтаблиці:

CREATE TABLE AllUser
( user_id INT AUTO_INCREMENT
, ...
, PRIMARY KEY (user_id)
) ;

------
--- Forum posts FK should reference the `AllUser` table

CREATE TABLE ActiveUser
( user_id INT 
, ...
, PRIMARY KEY (user_id)
, FOREIGN KEY (user_id)
    REFERENCES AllUser (user_id)
) ;

------
--- All other FKs should reference the `ActiveUser` table

Це, звичайно, ускладнить операцію вставки нового користувача. Будь-який новий користувач буде означати 2 вставки, по одному у кожній таблиці. Видалити користувача, проте, буде лише видаленням із ActiveUserтаблиці. Усі FK-файли будуть видалені з каскадом, за винятком дописів на форумі, в яких буде посилання на Alluserтаблицю (де видалення ніколи не відбудеться).


4

Немає природного способу зробити це, окрім використання information_schema.tables для запису всіх стовпців з опцією auto_increment.

Ви можете зібрати ці стовпчики наступним чином:

CREATE TABLE mysql.my_autoinc ENGINE=MyISAM
SELECT table_schema,table_name,auto_increment
FROM information_schema.tables WHERE 1=2;
ALTER TABLE mysql.my_autoinc ADD PRIMARY KEY (table_schema,table_name);
INSERT INTO mysql.my_autoinc
SELECT table_schema,table_name,auto_increment
FROM information_schema.tables WHERE auto_increment IS NOT NULL;

Створіть сценарій, який буде скинути значення auto_increment

AUTOINC_SCRIPT=/var/lib/mysql/ResetAutoInc.sql
mysql -u... -p... -AN -e"SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' AUTO_INCREMENT=',auto_increment,';') FROM mysql.my_autoinc" > ${AUTOINC_SCRIPT}

Потім ви можете зробити одне з двох:

ВАРІАНТ №1: Запуск сценарію вручну після запуску

mysql> source /var/lib/mysql/ResetAutoInc.sql

ВАРІАНТ №2: Попросіть mysqld виконати скрипт перед тим, як дозволити з'єднання

Вам доведеться додати цю опцію

[mysqld]
init-file=/var/lib/mysql/ResetAutoInc.sql

Таким чином, кожен раз при перезапуску mysql цей сценарій виконується на початку. Вам доведеться пам'ятати про відновлення /var/lib/mysql/ResetAutoInc.sql перед тим, як здійснити плановий перезапуск mysql.


3

В 5.5 Docs пропонує зберігати автоінкрементіруемого значення в інших місцях , як у вас вже є.

Альтернативним рішенням буде емуляція SEQUENCE, щоб ви не використовували автоматичне збільшення у власній таблиці. Це обговорювалося на SO раніше і знову . Блозі MySQL Performance згадує про нього.

Ще одна обробка даних MySQL, що інших RDBMS не має ...


2

Просто не видаляйте користувача. Реляційна цілісність важливіша. Якщо вам доведеться це через причини конфіденційності чи будь-що інше, просто змініть ім'я користувача на "видалене" та очистіть будь-які інші поля.


1

Це старе питання і досі актуальне.

1) Така поведінка фіксується в Mysql 8.0.

2) Одне з варіантів - використовувати фіктивний рядок для своїх даних, щоб тримати AUTO_INCREMENT вище певного значення. Не супер зручно залежно від того, що ви зберігаєте, але це просте рішення в деяких випадках.


0

У нас була потреба в цьому екстрапольованому рішенні для нашої власної системи на основі інструкцій на цій посаді. Якщо це може допомогти будь-кому досягти своєї мети ще простішим способом.

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

DROP PROCEDURE IF EXISTS `reset_auto_increments`;
DELIMITER $
CREATE PROCEDURE reset_auto_increments()
BEGIN

    DECLARE done INT DEFAULT 0;
    DECLARE schemaName VARCHAR(255) DEFAULT '';
    DECLARE liveTableName VARCHAR(255) DEFAULT '';
    DECLARE tombstoneTableName VARCHAR(255) DEFAULT '';
    DECLARE liveAutoIncrement INT DEFAULT 0;
    DECLARE tombstoneAutoIncrement INT DEFAULT 0;
    DECLARE newAutoIncrement INT DEFAULT 0;

    DECLARE autoIncrementPairs CURSOR FOR 
        SELECT
            liveTables.TABLE_SCHEMA AS schemaName,
            liveTables.TABLE_NAME AS liveTable, 
            tombstoneTables.TABLE_NAME AS tombstoneTable,
            liveTables.AUTO_INCREMENT AS live_auto_increment,
            tombstoneTables.AUTO_INCREMENT AS tombstone_auto_increment,
            GREATEST(liveTables.AUTO_INCREMENT, tombstoneTables.AUTO_INCREMENT) AS new_auto_increment
        FROM 
            information_schema.tables AS liveTables
            JOIN information_schema.tables AS tombstoneTables
                ON liveTables.TABLE_SCHEMA = tombstoneTables.TABLE_SCHEMA
                    AND CONCAT('deleted', UCASE(LEFT(liveTables.TABLE_NAME, 1)), SUBSTRING(liveTables.TABLE_NAME, 2))
                        = tombstoneTables.TABLE_NAME
        WHERE
            GREATEST(liveTables.AUTO_INCREMENT, tombstoneTables.AUTO_INCREMENT) IS NOT NULL;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    SET done = 0;

    SET schemaName = '';
    SET liveTableName = '';
    SET tombstoneTableName = '';
    SET liveAutoIncrement = 0;
    SET tombstoneAutoIncrement = 0;
    SET newAutoIncrement = 0;

    OPEN autoIncrementPairs;
    REPEAT

        FETCH autoIncrementPairs INTO 
            schemaName, 
            liveTableName, 
            tombstoneTableName, 
            liveAutoIncrement, 
            tombstoneAutoIncrement, 
            newAutoIncrement;

        SET @statement = CONCAT('ALTER TABLE ', schemaName, '.', liveTableName, ' AUTO_INCREMENT=', newAutoIncrement);
        PREPARE updateAutoIncrementStatement FROM @statement;
        EXECUTE updateAutoIncrementStatement;
        DEALLOCATE PREPARE updateAutoIncrementStatement;

    UNTIL done END REPEAT;

    CLOSE autoIncrementPairs;

END$

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