触发之前的CLOCK_TIMESTAMP是否确实与PG 12.3中的日志/提交顺序完全匹配?

问题描述

我有一个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()作为事物的度量标准?

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...