当整数列的 auto_increment 达到数据库中的 max_value 时会发生啥?
Posted
技术标签:
【中文标题】当整数列的 auto_increment 达到数据库中的 max_value 时会发生啥?【英文标题】:What happens when auto_increment on integer column reaches the max_value in databases?当整数列的 auto_increment 达到数据库中的 max_value 时会发生什么? 【发布时间】:2011-02-06 14:37:15 【问题描述】:我正在实现一个数据库应用程序,我将使用 JavaDB 和 mysql 作为数据库。我的表中有一个 ID 列,其类型为整数,我使用数据库 auto_increment-function 作为值。
但是当我收到超过 2(或 4)十亿个帖子并且整数还不够时会发生什么?整数是否溢出并继续,还是抛出了我可以处理的异常?
是的,我可以更改为 long as 数据类型,但如何检查何时需要?如果我使用 long 作为 ID 列的数据类型,我认为获取 last_inserted_id() 函数会出现问题。
【问题讨论】:
【参考方案1】:Jim Martin 来自 MySQL 文档§3.6.9. "Using AUTO_INCREMENT" 的评论:
以防万一,AUTO_INCREMENT 字段 /DOES NOT WRAP/。一旦达到字段大小的限制,INSERT 就会产生错误。 (根据杰里米·科尔)
使用 MySQL 5.1.45 进行快速测试会导致以下错误:
ERROR 1467 (HY000): 无法从存储引擎读取自增值
您可以在插入时测试该错误并采取适当的措施。
【讨论】:
正如我在测试中看到的,达到限制后每次(最大值)生成的增量数都是相同的。我没有收到预期的 SQL 错误。【参考方案2】:只是为了镇定神经,考虑一下:
假设您有一个数据库,每次用户在您的网站上执行某种交易时都会插入一个新值。
如果使用 64 位整数作为 ID,那么这是溢出的条件: 如果世界人口有 60 亿,那么如果地球上的每个人每天和每年(不休息)每秒执行一次交易,那么您的 id 将需要 80 多年才能完成。
即,只有谷歌需要在喝咖啡的时候偶尔模糊地考虑一下这个问题。
【讨论】:
抱歉,准确地说,这需要 9 年以上 :) 1 分钟后,360 bill tnx 将发生。 1小时后,21600账单。 1天验证5184000亿tnx。 1年:1892160千亿。 8 年后,将有 15,137,280 千亿美元保存在数据库中。 UNSIGNED BIGINT 的上限为 18,446,744 千亿。 您将在 1 年内额外获得一个零。所以大约是 97 年。 如果我有 2000 个代理发起插入攻击以启动多个线程/请求怎么办? .或者例如,我有一个带有(60.000 个条目)的历史上传功能,因此上传该历史将需要更少的请求。 我一直在想这个问题很长一段时间(比如,2 年,LOL)。如果发生这种情况有什么解决办法?如果脸书据说有10亿活跃用户每天至少3次cmet,而这些cmet只在一个表中,ID设置为int(11),如果达到该列的最大值怎么办?至少对于 Facebook 来说,这似乎是一个需要考虑的问题。 好吧,int(10) unsigned
,id 列在短短 2 个月内就达到了 237836414
或 uint_max 的 5.54%。所以,这是个问题。【参考方案3】:
通过查看最大的 ID,您将知道它何时会溢出。您应该在任何异常接近被抛出之前对其进行更改。
事实上,您应该从设计一个足够大的数据类型开始。即使您从一开始就使用 64 位 ID,您的数据库性能也不会受到影响。
【讨论】:
【参考方案4】:这里的答案说明了发生了什么,但只有一个答案说明了如何检测问题(然后仅在错误发生之后)。一般来说,能够在它们成为生产问题之前检测到这些东西是有帮助的,所以我编写了一个查询来检测何时将发生溢出:
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
希望这对某个地方的人有所帮助。
【讨论】:
【参考方案5】:对于 MySQL 5.6,3.6.9 Using AUTO_INCREMENT 说:
对 AUTO_INCREMENT 列使用最小的整数数据类型,该数据类型大到足以容纳您需要的最大序列值。当列达到数据类型的上限时,下一次尝试生成序列号失败。
【讨论】:
【参考方案6】:我想分享一下我刚刚对此的个人经历。使用 Nagios + Check_MK + NDOUtils。 NDOUtils 将所有检查存储在一个名为 nagios_servicechecks 的表中。主键是一个 auto_increment int 签名。当这个限制在一定范围内时,MySQL 会发生什么?好吧,就我而言,MySQL 删除了除最后一条之外的所有记录。桌子现在几乎是空的。每次插入新记录时,都会删除旧记录。不要为什么会发生这种情况,但事实是我丢失了所有记录。 IDOUtils 与 Icinga(不是 Nagios)一起使用,修复了通过 bigint 更改 int 的问题。它没有产生错误。
【讨论】:
以上是关于当整数列的 auto_increment 达到数据库中的 max_value 时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章