如果自增值达到了限制,该怎么办?

28

我正在进行一些研究,以解决可能发生的问题。 假设您拥有一个带有ID和名称字段的InnoDB MySQL表。ID字段具有BIGINT(20)并且是AUTO_INCREMENT,并且它是主键。

如果这个表已经满了,也就是说我们已经达到了ID的上限,无法再生成自增数字,那么您会怎么做?


codetinyint: 1 byte, -128 to +127 / 0 to 255 (unsigned) smallint: 2 bytes, -32,768 to +32,767 / 0 to 65,535 (unsigned) mediumint: 3 bytes, -8,388,608 to 8,388,607 / 0 to 16,777,215 (unsigned) int/integer: 4 bytes, -2,147,483,648 to +2,147,483,647 / 0 to 4,294,967,295 (unsigned) bigint: 8 bytes, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 / 0 to 18,446,744,073,709,551,615 (unsigned)code - mohamad mohamad
2
然后将bigint转换为无符号bigint。当它满了,你可能会创造MySQL数据库中最大数据量的记录。假设你不乱弄auto_increment列,让它自己工作就好了。我的意思是,你不需要担心这个。你看过最大可能的bigint值有多么巨大吗?我想说的是,90%的数据库用户从未达到auto_increment列的32位整数上限。而你正在谈论的是64位的值。 - fancyPants
2
您的系统将在您达到那个数字之前被淘汰。 - Juan
谢谢大家的回答。使用无符号整数是个好建议!谢谢 :) - user3676604
你应该对BIGINT(20)很满意,因为在你达到限制之前,太阳膨胀并吞噬地球的可能性更大。 - Max S.
3个回答

43

假设有一个类似于以下结构的表:

CREATE TABLE `tbl` (
    `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (`id`)
);

像下面这样的INSERT查询:

INSERT INTO tbl(id) VALUES (NULL);

在实际代码中表格中还有其他列,并且它们也在INSERT查询中出现,但我们可以安全地忽略它们,因为它们与该特定问题无关。

当列id的值达到其最大值时,使用上述查询将无法插入更多行到表中。下一个INSERT将失败并显示以下错误:

SQL错误(167):对于列'id',值超出范围。

如果列id的值存在间隙,则仍然可以插入使用表中不存在的值的行,但必须在INSERT查询中指定id的值。


不管怎样,如果您的AUTO_INCREMENT列的类型是BIGINT,您就不必担心。

假设代码每秒插入一百万条记录(这是高估的,甚至可以说是不可能的),则针对id列有足够的值可以支持接下来的500万年。或者如果该列没有UNSIGNED,则只有292,277年。


我曾目睹一台使用INT(11)(而不是UNSIGNED)作为记录网站访问信息的表的自增PK的现场Web服务器的行为。 在正常运行了几年后,在访问数量达到2^31(20多亿)时它失败了。

将列类型从INT更改为BIGINT不是二十亿条记录表的解决方案(完成需要很长时间,而当系统运行时,时间永远不够)。解决方案是创建一个具有相同结构但具有PK列的BIGINT和AUTO_INCREMENT列的初始值的新表,然后切换表:

CREATE TABLE `tbl_new` (
    `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (`id`)
) AUTO_INCREMENT=2200000000;

RENAME TABLE `tbl` TO `tbl_old`, `tbl_new` TO `tbl`;

我心中也有同样的解决方案,现在得到了你的确认。谢谢。 - Lakhan
重命名命令到底是在做什么?它是否将“tbl”和“tbl_new”合并? - Xavier Mukodi
语句RENAME TABLE的作用就是更改现有表的名称。在这里,我们需要将tbl_new重命名为tbl,但是表tbl已经存在,我们仍然需要它。这就是为什么我们首先将tbl重命名为tbl_old,然后将tbl_new放在tbl的位置上。需要进行两次重命名,但使用两个RENAME TABLE语句来执行它们会产生一个时间间隔,在此期间名为tbl的表不存在,这可能会破坏其他查询。通过使用单个语句执行两个重命名操作,该操作是原子性的,并且在表tbl不存在的情况下没有时间间隔。 - axiac
@XavierMukodi 了解一下RENAME TABLE MySQL语句。 - axiac
@axiac 我知道这是经过尝试和测试的,而且有效,但我仍然不理解它的本质。我们基本上只是用一个新的空表替换了“tbl”。但我们的目标是将主键类型更改为“BIGINT”。除非你省略了从“tbl_old”复制数据到“tbl”的部分。 - Xavier Mukodi
在答案的最后一部分,我描述了我们如何在凌晨3点解决了这个问题。第二天,我们更新了代码,如果在新表中找不到值,则会再次在旧表中搜索这些值,以此类推。复制数据不是一个选项,不仅在凌晨3点,而且在任何时间都不是。它需要很长时间并减慢网站的速度。 - axiac

4
tinyint: 1 byte, -128 to +127 / 0 to 255 (unsigned)
smallint: 2 bytes, -32,768 to +32,767 / 0 to 65,535 (unsigned)
mediumint: 3 bytes, -8,388,608 to 8,388,607 / 0 to 16,777,215 (unsigned)
int/integer: 4 bytes, -2,147,483,648 to +2,147,483,647 / 0 to 4,294,967,295 (unsigned)
bigint: 8 bytes, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 / 0 to 18,446,744,073,709,551,615 (unsigned)

你认为这个数字很小吗?也许在你达到这个数字之前,你已经死了。


-1

使用id varchar(255),然后在插入每条记录之前手动生成它(例如,将日期格式化为HH:mm:ss.SSS并与表名连接)。


如果您有新的问题,请通过单击提问按钮来提出。如果它有助于提供上下文,请包含此问题的链接。- 来自审核 - Dhaval Purohit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接