SQLite数据库中标识列的最大值是多少?

11
我有一个关于SQLite数据库的纯学术问题。
我正在使用SQLite.net在我的WinForm项目中使用数据库,在设置新表时,我开始思考ID列的最大值。
我使用IDENTITY作为我的[ID]列,根据SQLite.net DataType Mappings,它等同于DbType.Int64。我通常从零开始我的ID列(带有测试记录的行),并使数据库自动递增。
最大值(Int64.MaxValue)是9,223,372,036,854,775,807。对于我的目的,我甚至不会触及到达到该最大值的表面,但在达到最大值的数据库中会发生什么?在尝试了解此事时,我发现DB2显然将该值“包装”为负值(-9,223,372,036,854,775,807),并从那里递增,直到数据库无法插入行,因为ID列必须是唯一的。
这是否也发生在SQLite和/或其他数据库引擎中?

SQLite的官方文档在http://www.sqlite.org/autoinc.html中有详细介绍,我在下面添加了更详细的答案。 - Martin C.
4个回答

25

我怀疑没有人确切知道,因为如果每秒插入一百万行数据,需要约292,471年才能到达循环风险点-而数据库只存在了一小部分时间(实际上,人类也是如此;-)。


2
我总是喜欢这种理智检查,当我陷入问题时,虽然通常我不是那个想到它们的人。 :-/ - tgray
3
几乎不是"微小的一部分"。根据维基百科http://en.wikipedia.org/wiki/Homo_sapiens,人类已经存在了大约那个时期的三分之二。 - Jim Dennis

7

在SQLite中,IDENTITY不是自动递增的正确方式。这将要求您在应用程序层面进行递增。在SQLite shell中,请尝试以下操作:

create table bar (id IDENTITY, name VARCHAR);
insert into bar (name) values ("John");
select * from bar;

你会发现id只是一个空值。SQLite对IDENTITY没有特殊的意义,因此它基本上是一个普通的(未定义类型的)列。
另一方面,如果你这样做:
create table baz (id INTEGER PRIMARY KEY, name VARCHAR);
insert into baz (name) values ("John");
select * from baz;

我认为你期望的结果将会是1。

请注意,还有一个INTEGER PRIMARY KEY AUTOINCREMENT。基本区别在于AUTOINCREMENT确保键永不重用。因此,如果您删除John,则1将永远不会被重新用作id。无论哪种方式,如果您使用PRIMARY KEY(可选AUTOINCREMENT)并耗尽了ids,则SQLite应该失败,并显示SQLITE_FULL,而不是循环使用。

通过使用IDENTITY,您打开了(可能不相关的)可能性,即如果db满了,您的应用程序将错误地循环使用。这是完全可能的,因为SQLite中的IDENTITY列可以保存任何值(包括负整数)。再次尝试:

insert into bar VALUES ("What the hell", "Bill");
insert into bar VALUES (-9, "Mary");

这两种方法都是完全有效的。对于baz也是如此。然而,使用baz可以避免手动指定id。这样,您的id列中就永远不会有垃圾。


1
有趣的信息,我得去看看。现在,我使用Visual Studios 2008数据库设计师创建我的数据库。让我困惑的是sqlite本身是无类型的,所以我通常使用我链接的页面来确定数据类型,将第一列设置为名称:ID,类型:整数,不允许为空,然后将该列设置为主键。实际上,我对SQLite shell并不是很熟悉。不过还是谢谢你提供的信息! - Jared Harley

3
文档网站http://www.sqlite.org/autoinc.html表明,一旦ROWID达到其最大值,它将尝试通过随机化查找未使用的值。对于AUTOINCREMENT,如果表中存在最大值,则在尝试插入此表时会失败并出现SQLITE_FULL错误:

如果该表以前曾持有具有最大可能ROWID的行,则不允许新的INSERT,并且任何尝试插入新行都将失败并出现SQLITE_FULL错误。

这是必要的,因为AUTOINCREMENT保证ID单调递增。

1

我无法针对任何特定的DB2实现逻辑进行讲解,但您所描述的“环绕”行为是使用二进制补码实现签名的数字的标准行为。

至于实际会发生什么,完全取决于数据库如何处理它。问题出现在创建超过字段大小的ID时,因为引擎内部使用的数据类型不太可能超过64位。此时,任何人都可以猜测...用于开发引擎的内部语言可能会出错,数字可能会静默地环绕并导致主键冲突(假设存在冲突的ID),由于溢出而导致世界末日等等。

但从实际角度来看,Alex是正确的。在这里涉及到的行数的理论限制(假设每行只有一个ID,而不是任何作弊的身份插入骗局)基本上使情况无关紧要,因为即使以惊人的插入速率输入那么多行,我们也早已死亡,所以这没关系 :)


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