2

我正在制作一个可以在 SQL Server 和 PostgreSQL 上运行的应用程序,所以我在问这两个问题。

每当您创建一个唯一的主键(使用序列或自动增量类型的东西)并点击超过 40 亿条记录(32 位)时会发生什么?我并不是说我们的表将有 40 亿条记录,而是说已经创建了 40 亿条记录,因为 RID 只会增加。所以即使我删除了 39 亿条记录,我的 RID 仍然在 40 亿条范围内。那么会发生什么?它是把精度提高到 64 位还是翻转到 0 或者只是吐出一个非常严重的错误?我是否应该担心即使是 64 位 RID 也可能最终溢出?

另外,我该如何对抗呢?是否有某种清理选项或工具?我是否只需要每年创建自己的东西或完全重建表以获得一致的 RID?(因此也触及了许多使用这些 RID 的其他表是外键)

4

2 回答 2

3

默认情况下,PostgreSQL 会出错而不溢出:

# create sequence willyouwrap;
CREATE SEQUENCE
# select setval('willyouwrap', 9223372036854775807);
       setval        
---------------------
 9223372036854775807
(1 row)
# select nextval('willyouwrap');
ERROR:  nextval: reached maximum value of sequence "willyouwrap" (9223372036854775807)

从文档:

序列基于 bigint 算法,因此范围不能超过一个八字节整数的范围(-9223372036854775808 到 9223372036854775807)。在某些较旧的平台上,编译器可能不支持八字节整数,在这种情况下,序列使用常规整数算术(范围 -2147483648 到 +2147483647)。

但是,您可以使其循环:

CYCLE 选项允许序列在升序或降序分别达到最大值或最小值时回绕。如果达到限制,则生成的下一个数字将分别是最小值或最大值。

如果指定了 NO CYCLE,则在序列达到最大值后对 nextval 的任何调用都将返回错误。如果没有指定 CYCLE 或 NO CYCLE,则默认为 NO CYCLE。

不要与之抗争。花费额外的字节并保持简单。与拥有更大的键空间相比,您更有可能后悔添加额外的复杂层和/或维护任务。

于 2009-12-29T21:23:22.500 回答
1

在 SQL Server 上:这取决于 RID 列的类型。内部 IDENTITY 可以递增,但无法分配给 stoarge 列:

CREATE TABLE [t1] (
[tid] int IDENTITY (2147483647, 1) NOT NULL
  , name varchar(1)
) ON [PRIMARY]
GO
insert into t1(name) values('1')
insert into t1(name) values('1')

这会触发错误:

Msg 8115, Level 16, State 1, Line 2
Arithmetic overflow error converting IDENTITY to data type int.
Arithmetic overflow occurred.

但是具有足够存储空间的数字列会很好地增加:

CREATE TABLE [t1] (
[tid] numeric(38,0) IDENTITY (2147483647, 1) NOT NULL
  , name varchar(1)
) ON [PRIMARY]
GO
insert into t1(name) values('1')
insert into t1(name) values('1')

同样,一个 bigint 将在 2^^63-1 处溢出:

CREATE TABLE [t1] (
[tid] bigint IDENTITY (9223372036854775807, 1) NOT NULL
  , name varchar(1)
) ON [PRIMARY]
GO
insert into t1(name) values('1')
insert into t1(name) values('1')

但是具有足够存储空间的数字列会成功:

CREATE TABLE [t1] (
[tid] numeric(38,0) IDENTITY (9223372036854775807, 1) NOT NULL
  , name varchar(1)
) ON [PRIMARY]
GO
insert into t1(name) values('1')
insert into t1(name) values('1')
于 2009-12-29T21:20:01.070 回答