我们如何在 Informix 中为 SERIAL 类型的列循环序列号?
How can we cycle the serial number in Informix for column of type SERIAL?
我们遇到了一个问题,其中我们的 Informix DB 序列号列(SERIAL 类型)已达到最大限制。
每次遇到此问题时,我们都会手动将其重新设置为“1”。
有没有一种方法可以使用 sequence/cycle 来解决此问题而不对应用程序进行任何更改?
我们通过将值指定为“0”来插入数据,Informix 会自动处理它的递增。
您可以通过插入一个显式编号为 2,147,483,647 (231-1) 的行,然后插入另一个编号为 0 的行来回收 SERIAL 列。这会将计数器重置为 1,但随后尝试插入新序列号(插入值为 0)可能会与预先存在的行发生冲突,然后 INSERT 将失败(但下一次尝试将使用下一个序列号数)。
示例:
SQL[2416]: CREATE TABLE serial_wraparound
> (
> number SERIAL NOT NULL PRIMARY KEY,
> name VARCHAR(20) NOT NULL UNIQUE
> );
SQL[2417]: INSERT INTO serial_wraparound(number, name) VALUES(0, "The first");
SQL[2418]: INSERT INTO serial_wraparound(number, name) VALUES(0, "The second");
SQL[2419]: SELECT * FROM serial_wraparound;
1|The first
2|The second
SQL[2420]: INSERT INTO serial_wraparound(number, name) VALUES(2147483647, "The last");
SQL[2421]: SELECT * FROM serial_wraparound;
1|The first
2|The second
2147483647|The last
SQL[2422]: INSERT INTO serial_wraparound(number, name) VALUES(0, "Recycling");
SQL -268: Unique constraint (jleffler.u162_426) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at /dev/stdin:8
SQL[2423]: INSERT INTO serial_wraparound(number, name) VALUES(0, "Recycling");
SQL -268: Unique constraint (jleffler.u162_426) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at /dev/stdin:9
SQL[2424]: INSERT INTO serial_wraparound(number, name) VALUES(0, "Recycling");
SQL[2425]: SELECT * FROM serial_wraparound;
1|The first
2|The second
2147483647|The last
3|Recycling
SQL[2426]:
类似的行为适用于 SERIAL8 和 BIGSERIAL 列,只是环绕值是 9,223,372,036,854,775,807 (263-1)。如果您在 20 亿个序列号中重复使用 运行,也许您应该考虑更新您的应用程序以使用 BIGSERIAL,这样您就可以使用多达 9 个 quintillion 的数字。在长运行中它可能更简单。 (不要使用 SERIAL8(或 INT8);我提到它是为了完整性。新代码应该使用 BIGSERIAL 和 BIGINT。是的,这是有原因的。)
(命令解释器是我的 SQLCMD — 可从国际 Informix 用户组软件库的 ESQL/C 部分获得,IIUG。)
您还可以使用 ALTER TABLE 更改列中的值,但请注意,如果您不在 ALTER TABLE 中重新指定主键属性,主键属性将丢失。这是一个单一的语句序列(如果你真的很好奇,请编号为 2455):
+ DROP TABLE IF EXISTS serial_wraparound;
+ CREATE TABLE serial_wraparound (number SERIAL NOT NULL PRIMARY KEY, NAME VARCHAR(20) NOT NULL UNIQUE);
+ trace off;
+ INFO INDEXES FOR serial_wraparound
P|jleffler|u171_494|jleffler| 171_494|number|||||||||||||||
U|jleffler|u171_495|jleffler| 171_495|name|||||||||||||||
+ INSERT INTO serial_wraparound(number, NAME) VALUES(0, "The first");
+ INSERT INTO serial_wraparound(number, NAME) VALUES(0, "The second");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
+ ALTER TABLE serial_wraparound MODIFY(number SERIAL(248761) NOT NULL PRIMARY KEY);
+ trace off;
+ INFO INDEXES FOR serial_wraparound
P|jleffler|u171_498|jleffler| 171_494|number|||||||||||||||
U|jleffler|u171_495|jleffler| 171_495|name|||||||||||||||
+ continue on;
+ INSERT INTO serial_wraparound VALUES(0, "The modified");
+ INSERT INTO serial_wraparound VALUES(0, "The petrified");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
+ ALTER TABLE serial_wraparound MODIFY(number SERIAL(2147483647) NOT NULL PRIMARY KEY);
+ trace off;
+ INFO INDEXES FOR serial_wraparound
P|jleffler|u171_500|jleffler| 171_494|number|||||||||||||||
U|jleffler|u171_495|jleffler| 171_495|name|||||||||||||||
+ INSERT INTO serial_wraparound VALUES(0, "The inconsequential");
+ INSERT INTO serial_wraparound VALUES(0, "The ungainly");
SQL -268: Unique constraint (jleffler.u171_500) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at <<temp>>:27
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
+ INSERT INTO serial_wraparound VALUES(0, "The insubordinate");
SQL -268: Unique constraint (jleffler.u171_500) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at <<temp>>:29
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
+ INSERT INTO serial_wraparound VALUES(0, "The piscatorial");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
3|The piscatorial
+ INSERT INTO serial_wraparound VALUES(0, "The equatorial");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
3|The piscatorial
4|The equatorial
这表明 ALTER TABLE 可用于设置下一个值 — 首先使用 248,761(任意,即使不是随机的)然后再次使用 2,147,483,647。你不能减少这个数字,这就是为什么你必须仍然使用 231-1 技巧。
INFO INDEXES 语句用于确保保留主键约束——一些中间版本丢失了主键(唯一性)约束,给出了与我想要的不同的结果。 trace on
(和off
)命令关闭命令回显;您不想知道 INFO INDEXES 经历的卷积(或者您可以通过自己获取 SQLCMD 来了解)。它是由 SQLCMD(和 DB-Access)管理的语句; Informix 服务器本身不理解它。在这方面类似于OUTPUT和LOAD和UNLOAD等。
将列类型更改为 bigserial
,这是一种 64 位自动递增类型,无需进行更改即可适合应用程序的 long
数据类型。
正如 @JonathanLeffler
所指出的,如果您的应用程序检索最后生成的序列,您将不得不更改该代码,因为最后添加的 bigserial
是以不同的方式检索的。
我们遇到了一个问题,其中我们的 Informix DB 序列号列(SERIAL 类型)已达到最大限制。 每次遇到此问题时,我们都会手动将其重新设置为“1”。
有没有一种方法可以使用 sequence/cycle 来解决此问题而不对应用程序进行任何更改?
我们通过将值指定为“0”来插入数据,Informix 会自动处理它的递增。
您可以通过插入一个显式编号为 2,147,483,647 (231-1) 的行,然后插入另一个编号为 0 的行来回收 SERIAL 列。这会将计数器重置为 1,但随后尝试插入新序列号(插入值为 0)可能会与预先存在的行发生冲突,然后 INSERT 将失败(但下一次尝试将使用下一个序列号数)。
示例:
SQL[2416]: CREATE TABLE serial_wraparound
> (
> number SERIAL NOT NULL PRIMARY KEY,
> name VARCHAR(20) NOT NULL UNIQUE
> );
SQL[2417]: INSERT INTO serial_wraparound(number, name) VALUES(0, "The first");
SQL[2418]: INSERT INTO serial_wraparound(number, name) VALUES(0, "The second");
SQL[2419]: SELECT * FROM serial_wraparound;
1|The first
2|The second
SQL[2420]: INSERT INTO serial_wraparound(number, name) VALUES(2147483647, "The last");
SQL[2421]: SELECT * FROM serial_wraparound;
1|The first
2|The second
2147483647|The last
SQL[2422]: INSERT INTO serial_wraparound(number, name) VALUES(0, "Recycling");
SQL -268: Unique constraint (jleffler.u162_426) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at /dev/stdin:8
SQL[2423]: INSERT INTO serial_wraparound(number, name) VALUES(0, "Recycling");
SQL -268: Unique constraint (jleffler.u162_426) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at /dev/stdin:9
SQL[2424]: INSERT INTO serial_wraparound(number, name) VALUES(0, "Recycling");
SQL[2425]: SELECT * FROM serial_wraparound;
1|The first
2|The second
2147483647|The last
3|Recycling
SQL[2426]:
类似的行为适用于 SERIAL8 和 BIGSERIAL 列,只是环绕值是 9,223,372,036,854,775,807 (263-1)。如果您在 20 亿个序列号中重复使用 运行,也许您应该考虑更新您的应用程序以使用 BIGSERIAL,这样您就可以使用多达 9 个 quintillion 的数字。在长运行中它可能更简单。 (不要使用 SERIAL8(或 INT8);我提到它是为了完整性。新代码应该使用 BIGSERIAL 和 BIGINT。是的,这是有原因的。)
(命令解释器是我的 SQLCMD — 可从国际 Informix 用户组软件库的 ESQL/C 部分获得,IIUG。)
您还可以使用 ALTER TABLE 更改列中的值,但请注意,如果您不在 ALTER TABLE 中重新指定主键属性,主键属性将丢失。这是一个单一的语句序列(如果你真的很好奇,请编号为 2455):
+ DROP TABLE IF EXISTS serial_wraparound;
+ CREATE TABLE serial_wraparound (number SERIAL NOT NULL PRIMARY KEY, NAME VARCHAR(20) NOT NULL UNIQUE);
+ trace off;
+ INFO INDEXES FOR serial_wraparound
P|jleffler|u171_494|jleffler| 171_494|number|||||||||||||||
U|jleffler|u171_495|jleffler| 171_495|name|||||||||||||||
+ INSERT INTO serial_wraparound(number, NAME) VALUES(0, "The first");
+ INSERT INTO serial_wraparound(number, NAME) VALUES(0, "The second");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
+ ALTER TABLE serial_wraparound MODIFY(number SERIAL(248761) NOT NULL PRIMARY KEY);
+ trace off;
+ INFO INDEXES FOR serial_wraparound
P|jleffler|u171_498|jleffler| 171_494|number|||||||||||||||
U|jleffler|u171_495|jleffler| 171_495|name|||||||||||||||
+ continue on;
+ INSERT INTO serial_wraparound VALUES(0, "The modified");
+ INSERT INTO serial_wraparound VALUES(0, "The petrified");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
+ ALTER TABLE serial_wraparound MODIFY(number SERIAL(2147483647) NOT NULL PRIMARY KEY);
+ trace off;
+ INFO INDEXES FOR serial_wraparound
P|jleffler|u171_500|jleffler| 171_494|number|||||||||||||||
U|jleffler|u171_495|jleffler| 171_495|name|||||||||||||||
+ INSERT INTO serial_wraparound VALUES(0, "The inconsequential");
+ INSERT INTO serial_wraparound VALUES(0, "The ungainly");
SQL -268: Unique constraint (jleffler.u171_500) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at <<temp>>:27
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
+ INSERT INTO serial_wraparound VALUES(0, "The insubordinate");
SQL -268: Unique constraint (jleffler.u171_500) violated.
ISAM -100: ISAM error: duplicate value for a record with unique key.
SQLSTATE: 23000 at <<temp>>:29
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
+ INSERT INTO serial_wraparound VALUES(0, "The piscatorial");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
3|The piscatorial
+ INSERT INTO serial_wraparound VALUES(0, "The equatorial");
+ SELECT * FROM serial_wraparound;
1|The first
2|The second
248761|The modified
248762|The petrified
2147483647|The inconsequential
3|The piscatorial
4|The equatorial
这表明 ALTER TABLE 可用于设置下一个值 — 首先使用 248,761(任意,即使不是随机的)然后再次使用 2,147,483,647。你不能减少这个数字,这就是为什么你必须仍然使用 231-1 技巧。
INFO INDEXES 语句用于确保保留主键约束——一些中间版本丢失了主键(唯一性)约束,给出了与我想要的不同的结果。 trace on
(和off
)命令关闭命令回显;您不想知道 INFO INDEXES 经历的卷积(或者您可以通过自己获取 SQLCMD 来了解)。它是由 SQLCMD(和 DB-Access)管理的语句; Informix 服务器本身不理解它。在这方面类似于OUTPUT和LOAD和UNLOAD等。
将列类型更改为 bigserial
,这是一种 64 位自动递增类型,无需进行更改即可适合应用程序的 long
数据类型。
正如 @JonathanLeffler
所指出的,如果您的应用程序检索最后生成的序列,您将不得不更改该代码,因为最后添加的 bigserial
是以不同的方式检索的。