Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 自动递增主计数,在计数时留下间隙_Mysql_Primary Key - Fatal编程技术网

Mysql 自动递增主计数,在计数时留下间隙

Mysql 自动递增主计数,在计数时留下间隙,mysql,primary-key,Mysql,Primary Key,我有一张带有自动递增主键的表。这个表是用来存储数百万条记录的,我现在不需要删除任何内容。问题是,当插入新行时,由于某些错误,自动增量键会在自动增量ID中留下一些间隙。。例如,在5之后,下一个id是8,留下6和7的间隙。结果是当我数行时,结果是28000,但最大id是58000。原因可能是什么?我没有删除任何内容。我怎样才能解决这个问题 另外,我在插入记录时使用insert ignore,这样当我尝试在“唯一”列中插入重复条目时,它就不会出错。这是出于设计,而且总是会发生的 为什么? 让我们看两个

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


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

这是出于设计,而且总是会发生的

为什么?

让我们看两个正在进行插入的重叠事务

  • 事务1执行插入,获取值(比如42),做更多的工作
  • 事务2执行插入,获取值43,执行更多工作
然后

  • 事务1失败。向后滚动。42未使用
  • 事务2以43完成
如果保证连续的值,则每个事务都必须一个接一个地发生。可扩展性不是很强


另请参见(SQL Server,但适用相同的原则)

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

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

它使用的查询类似于

SELECT MAX(ai_col) FROM t FOR UPDATE;
这在不影响数据的情况下提高了并发性


要避免使用MyISAM而不是InnoDB作为存储引擎,您可以创建一个触发器来处理自动增量,如下所示:

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
也许(我还没有测试过)解决方案是将innodb\u autoinc\u lock\u模式设置为
0

根据这一点,可能会使事情变得慢一些(如果您在一个查询中执行多行插入),但应该消除间隙。

您可以尝试插入,如:

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

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

    (但如果发现重复条目,此方法不支持更新字段)

我不明白,为什么会发生这种情况?因为插入忽略或其他原因?如果顺序不正确,自动递增有什么意义?自动递增的唯一要求是它们是唯一的,它们不必是连续的。@如果顺序正确,以后的插入将具有更高的ID,它们只是不连续。如果您需要序列号,这里有一个基于触发器的解决方案:它甚至发生在不能在两个不同事务中同时使用的临时表上。我写了一个innodb gap答案,你似乎没有读到你链接的页面(??),上面说“在所有锁定模式(0、1和2)下,如果生成自动增量值的事务回滚,这些自动增量值将“丢失”你可能是对的。我知道最初的问题是关于编号方面的差距,即使没有错误/回滚。至少这是我的经验,也是我发现这个问题和答案的原因。这是一个好的做法吗?在并发插入发生的情况下,会不会在以后导致任何错误?这是一种糟糕的做法。如果从列表末尾删除了键,它们将被重新使用。这在内部不会是一个问题,因为外键可以防止对引用完整性的破坏,但是对您的数据的任何外部引用(可能该键被用作网站上的文章ID,或者您将数据导出到另一个将其合并到自己的系统中)都可能被“破坏”。如果没有在需要的地方定义适当的FK,内部引用完整性也会被破坏。此外,这将比使用内置增量支持效率低。引用项目是一个不错的观点,但不适用,因为这将在插入记录之前触发,而不是在记录确实存在时触发。如果未插入记录,MySql不会重用ID。如果取消40k记录插入事务,则在插入下一条记录时将留下40k间隙。虽然不是每种情况都适用,但定期批量导入大量记录是一种有效的解决方案。