我有同样的需求,我的解决方案基本上与@Edmund上面说的一样。
到目前为止我发现唯一的缺点是,由于我的查询查找序列列的MAX()值,在理论上,如果您删除最新行(通过这样做,您会减少最大记录的序列号)并添加一个新行,则该数字可能会被重新使用。
在将来的某个迭代中,我可能会创建一个专用表来存储每个单独序列的最大值,但我想对如何在重负载下工作进行一些性能测试。我正在有效地替换本机序列而没有它们的所有优化,这必须带来缺点。
在我的情况下,我在许多具有不同分区列的列上使用序列号,因此我创建了一个通用函数,我从触发器中调用它。
以下是该函数。您需要
hstore
扩展程序才能运行它。
CREATE OR REPLACE FUNCTION nssequence_nextval()
RETURNS trigger AS $$
DECLARE
query text;
nextval bigint;
BEGIN
IF TG_NARGS != 2 THEN
RAISE EXCEPTION '% did not supply nssequence_nextval with the required arguments.', TG_NAME;
END IF;
query := 'SELECT COALESCE(MAX(%I)::text, ''0'')::bigint + 1 FROM %I.%I WHERE organisation_id = $1.organisation_id AND %I = $1.%I'::text;
EXECUTE format(
query,
TG_ARGV[0],
TG_TABLE_SCHEMA, TG_TABLE_NAME,
TG_ARGV[1], TG_ARGV[1]
) USING NEW INTO nextval;
NEW := NEW #= hstore(TG_ARGV[0]::text, nextval::text);
RETURN NEW;
END
$$ LANGUAGE 'plpgsql';
这是每列的触发器(将方括号中的内容替换为实际名称):
CREATE OR REPLACE TRIGGER [nssequence_trigger_name]
BEFORE INSERT ON [schema.table]
FOR EACH ROW
EXECUTE PROCEDURE nssequence_nextval('[sequence_column_name]', '[partition_column_name]')
顺便说一下,我已经自动化了这个过程。我在每个序列列上使用一个列注释,例如
nssequence:partition_column_name
。我还编写了一个脚本,查找所有具有此类注释的列,并为它们添加触发器。
以下是查找所有序列列的查询:
SELECT
DISTINCT pgd.objoid,
c.table_schema,
c.table_name,
c.column_name,
pgd.description
FROM pg_catalog.pg_statio_all_tables as st
INNER JOIN pg_catalog.pg_description pgd ON (
pgd.objoid = st.relid
)
INNER JOIN information_schema.columns c ON (
pgd.objsubid = c.ordinal_position
AND c.table_schema = st.schemaname
AND c.table_name = st.relname
)
INNER JOIN information_schema.tables t ON (
t.table_type = 'BASE TABLE'
)
WHERE
t.table_schema != 'information_schema'
AND t.table_schema NOT LIKE 'pg_%'
AND pgd.description LIKE 'nssequence%'
最后,我还设置了一个清理机制,用于查找在不存在的列上创建的触发器或不再表示为序列号的触发器,但这可能对本答案来说过于详细了。