14

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

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

4

5 回答 5

20

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

为什么?

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

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

然后

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

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

另请参阅是否插入的记录总是接收连续的标识值(SQL Server 但同样的原则适用)

于 2013-05-16T08:40:44.000 回答
2

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

当您查看“<a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html" rel= 上的文档时,这确实不是问题“nofollow noreferrer">AUTO_INCREMENT 在 InnoDB 中的处理”它基本上说 InnoDB 使用一个特殊的表在启动时进行自动增量

它使用的查询类似于

SELECT MAX(ai_col) FROM t FOR UPDATE;

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

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

于 2013-05-16T08:47:20.787 回答
2

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

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
于 2016-01-22T13:53:19.243 回答
1

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

于 2016-02-23T16:26:10.843 回答
0

您可以尝试像这样插入:

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

这将尝试

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

    (但如果发现重复条目​​,此方法不支持更新字段)
于 2020-11-01T13:28:57.753 回答