Postgres动态创建序列

时间:2017-10-05 19:31:24

标签: database postgresql database-design

我正在编写一个应用程序,其中有多个用户,用户可以在应用程序中上传报告。

目前,我有一份报告'包含所有已提交报告的表格,其中包含“&id”标识。字段是表上的串行主键。

我已指定用户需要能够为其报告开始计数的前缀和数字指定的要求。例如,用户应该可以说他们的报告从ABC-100开始,然后下一个是ABC-101,ABC-102,依此类推。

我想实现这一点的方式是,当用户创建帐户时,他可以指定前缀和起始编号,我将创建一个postgres序列,其中包含指定的前缀名称和minValue是用户想要报告开始的数字。

然后,当用户提交新报告时,我可以将report_number标记为nextval(prefix_sequence)。理论上这可行,但我对postgres很新,我想要一些建议和反馈,如果这是一个很好的使用序列或有更好的方法。

1 个答案:

答案 0 :(得分:4)

这个区域可能不需要序列的主要好处 - 它们可以由多个事务同时使用。您可能也不希望有相应的缺点,即序列中的间隙是正常的。如果你有并发事务,回滚等,那么获得1, 2, 4, 7, 8, 12, ...之类的输出是很正常的。

在这种情况下,使用计数器会更好。当用户创建帐户时,请在account_sequences表格中创建一行,例如(account_id, counter)将它存储在主帐户表中,因为您将锁定并更新它,并且您希望最小化VACUUM工作量。

e.g。

CREATE TABLE account_sequences
(
    account_id integer PRIMARY KEY REFERENCES account(id),
    counter integer NOT NULL DEFAULT 1,
);

现在编写一个简单的LANGUAGE SQL函数,如

CREATE OR REPLACE FUNCTION account_get_next_id(integer)
RETURNS integer VOLATILE LANGUAGE sql AS
$$
UPDATE account_sequences
SET counter = counter + 1
WHERE account_id = $1
RETURNING counter
$$;

然后,您可以使用此代替nextval。 这将起作用,因为UPDATE相关account_sequences行的每个事务都会锁定它所持有的行,直到它提交或回滚为止。尝试获取同一帐户ID的其他交易将等待其完成。

欲了解更多信息,请搜索“postgresql gapless sequence”。

如果需要,您也可以使SQL函数获取前缀,使用format将其与生成的值连接,并返回text结果。如果将prefix text NOT NULL列放入account_sequences表格中,这会更容易,因此您可以执行以下操作:

CREATE OR REPLACE FUNCTION account_get_next_id(integer)
RETURNS text VOLATILE LANGUAGE sql AS
$$
UPDATE account_sequences
SET counter = counter + 1
WHERE account_id = $1
RETURNING format('%s%s', prefix, counter)
$$;

顺便说一下,采用使用SELECT max(id) ...子查询的天真方法。它是完全并发 - 不安全的,如果同时运行多个事务,它将产生错误的结果或错误。加上它很慢。