问题描述
我有一个Postgres 12.3问题:我可以依靠触发器中的CLOCK_TIMESTAMP()
在中准确地标记一个updated_dts
时间戳,与更改要提交的顺序相同永久数据?
表面上,这听起来像是一个愚蠢的问题,但是我只是花了两个时间来追踪非Postgres系统中超级稀有的种族状况,而该状况正是基于这种行为。 (滞后的提交使它们的“最后看到的值”跟踪数据不可靠。)现在,我试图找出CLOCK_TIMESTAMP()
是否可能与WAL中记录的更改顺序不完全匹配。
很容易看到Now/TRANSACTION_TIMESTAMP/CURRENT_TIMESTAMP
在返回事务开始时间而不是完成时间时如何发生。在那种情况下,记录时间戳和日志顺序不一致的时间戳序列非常容易。但是我不知道是否有可能以与BEFORE
触发器CLOCK_TIMESTAMP()
值不同的顺序保存提交。
对于背景,我们需要100%可靠的时间表以供外部搜索使用。据我了解,我可以使用逻辑复制来创建一个复制对象,并使用复制目标端触发器来标记从日志中重放的更改。我不清楚的是,是否有可能在单个服务器上从CLOCK_TIMESTAMP()
获得相同的保真度。
我还没有深入了解Postgres内部的知识,也没有看到请求是如何交错的,执行的粒度如何,并且希望这里的人能确切地知道。如果这是其中一个PG邮件列表的更多问题,请告诉我。
-谢谢
下面是一些有关如何构建时间戳的示例代码。它可以正常工作,但不能证明有关具有大量并发进程的行为。
---------------------------------------------
-- Create the trigger function
---------------------------------------------
DROP FUNCTION IF EXISTS api.set_updated CASCADE;
CREATE OR REPLACE FUNCTION api.set_updated()
RETURNS TRIGGER
AS $BODY$
BEGIN
NEW.updated_dts = CLOCK_TIMESTAMP();
RETURN NEW;
END;
$BODY$
language plpgsql;
COMMENT ON FUNCTION api.set_updated() IS 'Sets updated_dts field to CLOCK_TIMESTAMP(),if the record has changed..';
---------------------------------------------
-- Create the table
---------------------------------------------
DROP TABLE IF EXISTS api.numbers;
CREATE TABLE api.numbers (
id uuid NOT NULL DEFAULT extensions.gen_random_uuid (),number integer NOT NULL DEFAULT NULL,updated_dts timestamptz NOT NULL DEFAULT 'epoch'::timestamptz
);
---------------------------------------------
-- Define the triggers (binding)
---------------------------------------------
-- NOTE: I'm guessing that in production that I can use DEFAULT CLOCK_TIMESTAMP() instead of a BEFORE INSERT trigger,-- I'm using a distinct DEFAULT value,as I want it to pop out if I'm not getting the trigger to fire.
CREATE TRIGGER trigger_api_number_before_insert
BEFORE INSERT ON api.numbers
FOR EACH ROW
EXECUTE PROCEDURE set_updated();
CREATE TRIGGER trigger_api_number_before_update
BEFORE UPDATE ON api.numbers
FOR EACH ROW
WHEN (OLD.* IS disTINCT FROM NEW.*)
EXECUTE PROCEDURE set_updated();
---------------------------------------------
-- INSERT some data
---------------------------------------------
INSERT INTO numbers (number) values (1),(2),(3);
---------------------------------------------
-- Take a look
---------------------------------------------
SELECT * from numbers ORDER BY updated_dts ASC; -- The values should be listed as 1,2,3 as oldest to newest.
---------------------------------------------
-- UPDATE a row
---------------------------------------------
UPDATE numbers SET number = 11 where number = 1;
---------------------------------------------
-- Take a look
---------------------------------------------
SELECT * from numbers ORDER BY updated_dts ASC; -- The values should be listed as 2,3,11 as oldest to newest.
解决方法
不,您不能依赖于触发器执行期间(或评估clock_timestamp()
子句时)的DEFAULT
顺序与提交顺序相同。
提交总是会在函数调用之后进行,并且您无法控制它们之间花费的时间。
但是令我惊讶的是,这对您来说是个问题。通常,提交时间不可见或不相关。您为什么不简单地接受clock_timestamp()
作为事物的度量标准?