【问题标题】:auto increment primary leaving gaps in counting自动递增主要在计数中留下空白
【发布时间】:2013-05-11 01:36:38
【问题描述】:

我有一个带有自动递增主键的表。该表旨在存储数百万条记录,我现在不需要删除任何内容。问题是,当插入新行时,由于某些错误,自动增量键在自动增量 id 中留下了一些间隙。例如,在 5 之后,下一个 id 是 8,留下 6 和 7 的间隙.结果是当我计算行数时,结果为28000,但最大id为58000。可能是什么原因?我没有删除任何东西。我该如何解决这个问题。

附:我在插入记录时使用插入忽略,这样当我尝试在唯一列中插入重复条目时它不会出错。

【问题讨论】:

标签: mysql primary-key


【解决方案1】:

您可以尝试像这样插入:

insert ignore into table select (select max(id)+1 from table), "value1", "value2" ;

这会试试

  • 使用最后一个未使用的 id 插入新数据(非自动增量)
  • 如果在唯一字段中发现重复条目​​,请忽略它
  • 否则正常插入新数据

    (但此方法不支持在发现重复条目​​时更新字段)

【讨论】:

    【解决方案2】:

    这是 MySQL 的存储引擎 InnoDB 的问题。

    这真的不是问题,因为当您查看“AUTO_INCREMENT Handling in InnoDB”上的文档时,它基本上说 InnoDB 使用一个特殊的表在启动时执行自动增量

    它使用的查询类似于

    SELECT MAX(ai_col) FROM t FOR UPDATE;
    

    这可以提高并发性,而不会真正影响您的数据。

    如果没有这个使用 MyISAM 而不是 InnoDB 作为存储引擎

    【讨论】:

      【解决方案3】:

      也许(我还没有测试过)解决方案是将innodb_autoinc_lock_mode 设置为0。 根据http://dev.mysql.com/doc/refman/5.7/en/innodb-auto-increment-handling.html 的说法,这可能会使事情变慢(如果您在单个查询中执行多行插入),但应该消除间隙。

      【讨论】:

      • 您似乎没有阅读您链接的页面 (??),其中指出“在所有锁定模式(0、1 和 2)中,如果生成自动增量值的事务回滚,这些自动增量值“丢失”了。”
      • 你可能是对的。我知道最初的问题是关于编号的差距,即使没有错误/回滚。至少这是我的经验,也是我找到这个问题和答案的原因
      【解决方案4】:

      您可以创建一个触发器来处理自动增量:

      CREATE DEFINER=`root`@`localhost` TRIGGER `mytable_before_insert` BEFORE INSERT ON `mytable` FOR EACH ROW 
      BEGIN
        SET NEW.id = (SELECT IFNULL(MAX(id), 0) + 1 FROM mytable);;
      END
      

      【讨论】:

      • 这是一个好习惯吗?那么在并发插入的情况下,以后会不会报错呢?
      • 这是不好的做法。如果从列表末尾删除键,它们将被重用。这不会是内部问题,因为外键可以防止损坏参照完整性,但是对您的数据的任何外部引用(可能该键被用作网站上的文章 ID,或者您将数据导出到另一个系统将其合并到它自己的)可能被“破坏”。如果您没有在需要的地方定义正确的 FK,内部参照完整性也会被破坏。这也比使用内置的增量支持效率低。
      • 引用文章是个好点,但不适用,因为这将在插入记录之前触发,而不是在记录存在时触发。如果没有插入记录,MySql 不会重用 id。如果取消一个 40k 记录的插入事务,那么在插入下一条记录时会留下 40k 的间隙。虽然不是在所有情况下都理想,但它是定期批量导入大量记录的有效解决方案。
      【解决方案5】:

      这是设计使然,并且总会发生。

      为什么?

      让我们采取 2 个正在执行 INSERT 的重叠事务

      • 事务 1 执行 INSERT,获取值(比如 42),完成更多工作
      • 事务 2 执行 INSERT,获得值 43,完成更多工作

      然后

      • 事务 1 失败。回滚。 42 未使用
      • 事务 2 以 43 完成

      如果保证连续值,则每笔交易都必须一个接一个地发生。不是很可扩展。

      另见Do Inserted Records Always Receive Contiguous Identity Values(SQL Server,但同样的原则适用)

      【讨论】:

      • 我不明白,为什么会这样?因为插入忽略或其他原因?如果顺序不正确,自动递增有什么意义?
      • 自增的唯一要求是它们是唯一的,它们不必是连续的。
      • @Sourabh 它们的顺序正确,以后的插入将具有更高的 ID,它们只是不连续。如果您需要序列号,这里有一个基于触发器的解决方案:stackoverflow.com/questions/3292197/…
      • 它甚至发生在不能在两个不同事务中同时使用的临时表上。
      • 我写了一个innodb差距答案Over Here。你可以不让它们发生,但要付出代价。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      相关资源
      最近更新 更多