当整数列上的auto_increment达到数据库中的max_value时会发生什么?


72

我正在实现一个数据库应用程序,我将同时使用JavaDB和MySQL作为数据库。我的表中有一个ID列,其类型为整数,并且使用数据库auto_increment-function作为值。

但是,当我获得超过2(或4)十亿个帖子并且整数不够时,会发生什么?整数溢出并继续还是抛出了我可以处理的异常?

是的,我可以更改为数据类型,但是如何检查何时需要?而且我认为,如果我将long用作ID列的数据类型,则获取last_inserted_id()函数会出现问题。

Answers:


52

吉姆·马丁(Jim Martin)的评论来自§3.6.9。MySQL文档的“使用AUTO_INCREMENT”

万一有任何疑问,请在AUTO_INCREMENT字段/ DOES NOT WRAP /中输入。一旦达到字段大小的限制,INSERT就会产生错误。(根据杰里米·科尔)

使用MySQL 5.1.45进行的快速测试会导致以下错误:

错误1467(HY000):无法从存储引擎读取自动增量值

您可以在插入时测试该错误并采取适当的措施。


正如我在测试中看到的那样,达到限制后,每次生成的增量数都是相同的(最大值)。我没有收到预期的SQL错误。
维克多

52

为了使神经平静,请考虑以下事项:

假设您有一个数据库,每次用户在您的网站上执行某种交易时,该数据库都会插入一个新值。

以64位整数作为ID,那么这就是溢出的条件:在60亿的世界人口中,如果地球上每个人每天且每年(每年不休息)每秒执行一次事务,则将花费超过80年为您的身份证环绕。

即,只有Google偶尔需要在喝咖啡休息时间时隐约考虑这个问题。


4
抱歉,正确的说法将需要9年以上的时间:) 1分钟后,将发生360笔账单tnx。1小时后,产生21600比尔。在1天之内,将验证518400亿吨。1年:1892160万亿。8年后,数据库中将节省15137280亿亿美元。UNSIGNED BIGINT的限制是18,446,744千亿。
tobia.zanarella '07年

2
您将在一年内多获得零零。因此大约需要97年。
lockscope13年

1
如果我有2000个代理进行插入攻击,启动多个线程/请求,该怎么办?。或者例如,我有一个具有(60.000个条目)的历史记录上载功能,因此上载该历史记录将需要较少的请求。
Anestis Kivranoglou 2014年

我一直在想这个问题很长时间(例如2年,哈哈)。如果发生了什么解决方案?如果假设有10亿活跃的Facebook评论用户每天至少3次,并且这些评论仅存在于一个表中,且其ID设置为int(11),那么,如果达到该列的最大值,该怎么办?至少对于facebook而言,这似乎是一个值得思考的问题。
christianleroy

对我来说,int(10) unsignedid列237836414仅用了2个月便达到了uint_max的5.54%。所以,这是一个问题。
majidarif

10

通过查看最大的ID,您将知道何时会溢出。您应该在任何异常甚至差一点被抛出之前就做好更改。

实际上,您应该从一个足够大的数据类型开始设计。即使从一开始就使用64位ID,数据库性能也不会受到影响。


8

这里的答案说明发生了什么,但是只有一个答案说明了如何检测问题(然后仅在错误发生之后)。通常,能够在这些问题成为生产问题之前对其进行检测是有帮助的,因此我编写了一个查询来检测何时将要发生溢出:

SELECT
  c.TABLE_CATALOG,
  c.TABLE_SCHEMA,
  c.TABLE_NAME,
  c.COLUMN_NAME
FROM information_schema.COLUMNS AS c
JOIN information_schema.TABLES AS t USING (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME)
WHERE c.EXTRA LIKE '%auto_increment%'
  AND t.AUTO_INCREMENT / CASE c.DATA_TYPE
      WHEN 'TINYINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 255, 127)
      WHEN 'SMALLINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 65535, 32767)
      WHEN 'MEDIUMINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 16777215, 8388607)
      WHEN 'INT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 4294967295, 2147483647)
      WHEN 'BIGINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', '18446744073709551615', 9223372036854775807) # need to quote because column type defaults to unsigned.
      ELSE 0
    END > .9; # 10% buffer

希望这对某人有所帮助。


0

对于MySQL 5.6、3.6.9,在中使用AUTO_INCREMENT表示:

为AUTO_INCREMENT列使用最小的整数数据类型,该数据类型应足够大以容纳所需的最大序列值。当列达到数据类型的上限时,下一次生成序列号的尝试将失败。


-1

我想分享一下我的个人经历。使用Nagios + Check_MK + NDOUtils。NDOUtils将所有检查存储在名为nagios_servicechecks的表中。主键是一个auto_increment整数符号。超出此限制时,MySQL会发生什么?好吧,就我而言,MySQL删除了除最后一条以外的所有记录。该表现在几乎是空的。每次插入新记录时,都会删除旧记录。别为什么会这样,但是事实是我丢失了所有记录。与Icinga(不是Nagios)一起使用的IDOUtils通过bigint修复了更改int的问题。它没有产生错误。

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.