重启服务器后,防止在Innodb数据库中重置auto_increment id


11

我最近读到,由于服务器重启时InnoDB如何重新计算AUTO_INCREMENT值,所以ID列表高端上的任何记录都可能重用了它们的ID。

通常,这不是问题,因为删除用户后,与ID关联的所有内容也会从其他表中删除。

但是,我故意将他们的论坛帖子保留为孤立状态,标记为“由= User#123 =“发表”,以便保留过去的对话。显然,如果ID被重用,这将是一个问题。

我以前从未遇到过此问题,因为总是有足够的新用户,因此不太可能以这种方式重复使用ID。但是,在我的新项目中,注册很少,并且频繁删除不活动的用户(尤其是因为“ Open Alpha”帐户仅持续三天作为预览),这种ID重用现在已经发生了三分之三。

我通过在其他位置保存AUTO_INCREMENT的正确值并使用它而不是依赖内部值来“解决”该问题。有实际的方法让InnoDB记住实际的上一个值吗?


你有读过的文章吗?
gbn 2012年



ALTER TABLE table_name ENGINE = MyISAM对我有用。我们的表始终保持很小,因此不需要InnoDB。

1
@QuickFix您应该添加的一些细节,为什么这个作品。
Max Vernon

Answers:


5

(通过从不删除来避免出现此问题)

由于要"Posted by =User #123="在使用删除用户后保留信息id=123,因此您也可以考虑使用2个表来存储用户数据。一种用于Active用户,另一种用于所有用户(包括从活动用户中删除的用户)。永远不要从AllUser表中删除这些ID :

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时,都会在开始时执行此脚本。您必须记住在执行计划的mysql重新启动之前,重新生成/var/lib/mysql/ResetAutoInc.sql。


3

5.5文档建议别处存储自动递增值,你已经有了。

另一种解决方案是模拟SEQUENCE,这样您就不必在实际表本身中使用自动增量。这已SO之前讨论的再次。在MySQL性能博客提到它。

其他RDBMS所没有的另一个MySQL数据...


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 ;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.