Fat*_*tie 4 postgresql sequence amazon-rds
所以是一个 postgres 数据库(特别是一个 AmazonRDS 实例 fwiw)。
安排事情以获取任何记录的最后更新(或创建)时间很容易。
该信息将是日期时间。
我想要实现的是:想象一个整数,sequenceNumber,它对数据库来说是原子的和全局的。
简单地说,每个表都会有一个 sequenceNumber 字段。
任何时候任何记录(即,在任何表中)被更新(或创建),它都会获得下一个序列号。
您知道如何拥有对数据库一无所知的程序员朋友。海浪。我的白痴解决方案是,在整个代码库中,每次创建或修改记录时,一定要记得更新它的序列号。(当然,只需要一个全局系统来给出下一个原子序列号。)
对此的声音解决方案是什么?
事实上,它是否已经以某种我不知道的方式完全可用,或者?
正如a_horse_with_no_name最初在问题评论中建议的那样:
--assuming we have tables: a, b, ...
CREATE TABLE a
(
a_id integer NOT NULL PRIMARY KEY,
a_name text
) ;
CREATE TABLE b
(
b_id integer NOT NULL PRIMARY KEY,
b_name text
) ;
Run Code Online (Sandbox Code Playgroud)
首先我们创建一个全局序列并在每个表中添加一列:
-- create one global sequence to be used by all tables
CREATE SEQUENCE global_sequence_number ;
-- add a column in each table, that uses the same sequence
ALTER TABLE a
ADD COLUMN global_sequence_id INT NOT NULL
DEFAULT nextval('global_sequence_number'::regclass) ;
ALTER TABLE b
ADD COLUMN global_sequence_id INT NOT NULL
DEFAULT nextval('global_sequence_number'::regclass) ;
Run Code Online (Sandbox Code Playgroud)
创建触发器函数(一个)和UPDATE
触发器(每个表一个):
-- create a trigger function to update the column
CREATE OR REPLACE FUNCTION update_global_sequence_id()
RETURNS TRIGGER AS
$$
BEGIN
NEW.global_sequence_id = nextval('global_sequence_number'::regclass);
RETURN NEW;
END;
$$ language 'plpgsql';
-- add a trigger, in each table
CREATE TRIGGER update_a_global_sequence_id
BEFORE UPDATE ON a FOR EACH ROW
EXECUTE PROCEDURE update_global_sequence_id();
CREATE TRIGGER update_b_global_sequence_id
BEFORE UPDATE ON b FOR EACH ROW
EXECUTE PROCEDURE update_global_sequence_id();
Run Code Online (Sandbox Code Playgroud)
和利润:
-- example of use
INSERT INTO a (a_id, a_name)
VALUES
(1, 'a'), (2, 'b') ;
INSERT INTO b (b_id, b_name)
VALUES
(3, 'c'), (4, 'd'), (5, 'e') ;
SELECT *
FROM a FULL JOIN b ON FALSE
ORDER BY COALESCE(a.global_sequence_id, b.global_sequence_id) ;
Run Code Online (Sandbox Code Playgroud)
- 输出 1 一个 1 2 b 2 3 c 3 4 天 4 5 和 5
在一些更新之后,检查触发器是否工作:
-- lets do some updates:
UPDATE a SET a_name = 'aa' WHERE a_id = 1 ;
UPDATE b SET b_name = 'cc' WHERE b_id = 3 ;
-- and see what happened
SELECT *
FROM a FULL JOIN b ON FALSE
ORDER BY COALESCE(a.global_sequence_id, b.global_sequence_id) ;
Run Code Online (Sandbox Code Playgroud)
- 输出 2 b 2 4 天 4 5 和 5 1 aa 6 -- 序列更新为 6 3 cc 7 -- 序列更新为 7
社区 Wiki 回答记录了Craig Ringer对该问题的评论
关于这一点的快速警告。如果您打算这样做,以便您的应用程序可以记住“上次看到的序列号”并根据序列号进行某种同步或批处理,则它会丢失行。事务的提交顺序不一定与它们调用的顺序相同nextval
。
具体来说,如果三个 xacts A、B 和 C 的值分别为 1、2 和 3,那么它们几乎都在同一时间提交,C 可能首先变得可见,因此您会在表中看到 3,但 1 和 2 不是那里呢。诸如此类的事情。PostgreSQL 的逻辑解码通过为您提供严格提交顺序的数据流来解决这个问题,以防这与您正在处理的问题有关。
您调用nextval(...)
以获取序列值的顺序不一定与 xacts 提交的顺序相同,除非应用程序在外部强制执行该顺序。未提交的行对 不可见SELECT
。所以你可能SELECT * FROM the_table WHERE the_sequence_column > 0
因为你上次看到的 ID 是 0。你发现the_sequence_column
返回的最大值是 3。所以下次你SELECT ... WHERE the_sequence_column > 3
. 但实际上,1
并且2
可能在你看到 3之后就犯了,所以你没有在第一个中得到它们SELECT
,你也不会在后者中得到它们。
您可能会想“我只会保留一个我还没有看到的 ID 列表”。但这会表现得很糟糕,而且它也无法应对回滚的 xact,在服务器崩溃和重新启动期间跳过序列值等。它们永远不会被重用并被丢弃。因此,您的应用程序将继续寻找永远不会存在的值。除非您可以让您的应用程序强制执行提交顺序,以便它按照分配 ID 的顺序提交(如果一个 xact 获得 ID 1、4 和 7,而另一个 xact 获得 ID 2 和 3,这可能是不可能的)...您的解决方案不会真正起作用,这就是为什么您可能希望研究逻辑解码,以稳健、有序、可靠的方式从数据库中获取变更流。例如,有一些插件可以流式传输 json。
归档时间: |
|
查看次数: |
460 次 |
最近记录: |