【问题标题】:Reusage of lost AUTO_INCREMENT values重用丢失的 AUTO_INCREMENT 值
【发布时间】:2013-05-18 12:10:23
【问题描述】:

我试图了解 innodb 关于重用可能出现在 AUTO_INCREMENT 值序列中的间隙的确切行为。问题是在我看来,我在文档中发现了两个相互矛盾的描述。

  1. http://dev.mysql.com/doc/refman/5.6/en/innodb-auto-increment-configurable.html

在所有锁定模式(0、1 和 2)中,如果生成的事务 自动增量值回滚,那些自动增量值是 “丢失”。一旦为自增列生成了一个值,它 不能回滚,无论“INSERT-like”语句是否 已完成,以及包含的事务是否滚动 背部。此类丢失的值不会被重复使用。

2 。 http://dev.mysql.com/doc/refman/5.6/en/innodb-restrictions.html

当你重新启动 MySQL 服务器时,InnoDB 可能会重用一个旧值 为 AUTO_INCREMENT 列生成但从未存储(即 在滚动的旧事务期间生成的值 返回)。

那么这些丢失的值会被重用吗?如果它们确实会在重新启动 MYSQL 服务器后被重用,那么考虑到 InnoDB 通过执行等效的语句来确定新的 AUTO_INCREMENT 值,这怎么可能

从 t 中选择 MAX(ai_col) 进行更新

?

【问题讨论】:

    标签: mysql innodb


    【解决方案1】:

    我相信这意味着

    如果生成自动递增值的事务回滚, 除非重新启动服务器,否则这些自动增量值会“丢失” 在需要生成任何进一步的自动增量值之前

    我找不到确认此行为的权威参考,但以下测试似乎同意:

    bash > mysql test
    
    mysql > CREATE TABLE ai (id INT AUTO_INCREMENT PRIMARY KEY);
    mysql > BEGIN;
    mysql > INSERT INTO ai VALUES (NULL);
    mysql > ROLLBACK;
    mysql > BEGIN;
    mysql > INSERT INTO ai VALUES (NULL);
    mysql > COMMIT;
    mysql > SELECT * FROM ai;
    +----+
    | id |
    +----+
    |  2 |
    +----+
    mysql > BEGIN;
    mysql > INSERT INTO ai VALUES (NULL);
    mysql > ROLLBACK;
    mysql > -- expecting auto-increment value "3" to be "consumed"
    mysql > quit;
    
    bash > service mysql restart
    bash > mysql test
    
    mysql > BEGIN;
    mysql > INSERT INTO ai VALUES (NULL);
    mysql > COMMIT;
    mysql > SELECT * FROM ai;
    +----+
    | id |
    +----+
    |  2 |
    |  3 |
    +----+
    

    【讨论】:

    • 但是文档说 AUTO_INCREMENT 计数器仅存储在内存中,并且在每次重新启动时都会重新计算,因此这意味着重新启动不会像您假设的那样影响计数器 - “除非服务器在进一步启动之前重新启动需要生成自增值”...
    • 我看不出矛盾。如果自动增量值仅存储在内存中,则“丢失”的值在重新启动时“恢复”是有意义的。在上述场景中:a-i 值123 被消耗,(但只有值2 被真正使用)。重新启动时,MySQL 重新计算实际使用的最后一个 a-i 值是 2,因此下面的插入能够使用 a-i 值 3
    • 如果不存储值3,再次获得值3就不是问题了。但我问是否有可能获得值 1 打破我的 id 的升序。周围的人抱怨这是可能的!
    • Ew。我从来没有遇到过这种行为,但我真的不知道。
    【解决方案2】:

    第一种情况是正常行为,是您所期望的。

    第二种情况是一个奇怪的情况。

    假设我们正在为写入分配 1024,但写入或事务未完成,因为 MySQL 已停止或崩溃。在某些情况下,会记录 1024 的使用情况,因此接下来将分配 1025。但是,有一个小窗口没有记录1024的分配在表中用于启动。这解释了案例 2。

    此外,InnoDB 实际上并没有为新分配执行真正的 MAX(但 MyISAM 会)。它是等价的。但是它确实在启动时这样做

    还可以查看这些

    更新。

    问题中的第一个链接 (http://dev.mysql.com/doc/refman/5.6/en/innodb-auto-increment-traditional.html) 解释了这种行为。如果链接失效,请在下面选择引号:

    如果您为 InnoDB 表指定 AUTO_INCREMENT 列,则 InnoDB 数据字典中的表句柄包含一个称为自动增量计数器的特殊计数器,用于为该列分配新值。此计数器仅存储在主内存中,而不存储在磁盘上

    因此,这是一个运行时的事情,其中​​数字与实际表分开递增。这解释了差距:新值的分配与写入不同。

    InnoDB 使用以下算法为表 t 初始化自动增量计数器,该表包含名为 ai_col 的 AUTO_INCREMENT 列:服务器启动后,对于表 t 的第一次插入,InnoDB 执行与此语句等效的语句:

    因此,由于服务器重启而导致分配成功但写入失败的文件将被丢弃。

    【讨论】:

    • 是的,这种奇怪的行为只能用“InnoDB 实际上并没有做真正的 MAX”这一事实来解释,否则计数器将永远无法返回旧值。但是 MySql 到底是如何初始化计数器的呢?
    • @AndreyKon:它存储在一个单独的计数器中,该计数器在启动时被初始化。见docs.oracle.com/cd/E17952_01/refman-5.6-en/…这解释了一切
    • +1 是的:“在服务器启动后,对于第一次插入表 t,InnoDB 执行与此语句等效的语句:SELECT MAX(ai_col) FROM t FOR UPDATE;”跨度>
    • 但是,我宁愿这样说:“所以,一个成功的分配但[无论出于何种原因未写入]将被丢弃[如果稍后没有成功写入,则在服务器重新启动之前] "。
    猜你喜欢
    • 2012-04-02
    • 2013-12-22
    • 2023-03-21
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    • 2016-08-31
    • 2019-03-06
    相关资源
    最近更新 更多