这与Postgres由于并发更新而无法序列化访问的问题类似,但是由于FDW的特性,这些建议不适用
错误是"由于并发更新而无法序列化访问"。来自以下代码:
update fdw_table set last_new_data=clock_timestamp() where fn_name='something' and id=1234
问题似乎是fdw有更严格的事务级别,无法更改-或者至少这是我对文档postgresql.org/docs/current/postgres-fdw.html的理解。
我试着使用下面的
update fdw_table set last_new_data=clock_timestamp()
where fn_name='something' and id=(
select id from fdw_table
where fn_name='something' and id=1234
FOR UPDATE SKIP LOCKED
);
但是这仍然抛出错误。
这是预料之中的;参见contrib/postgres_fdw/connection.c
中begin_remote_xact
的以下评论:
/*
* Start remote transaction or subtransaction, if needed.
*
* Note that we always use at least REPEATABLE READ in the remote session.
* This is so that, if a query initiates multiple scans of the same or
* different foreign tables, we will get snapshot-consistent results from
* those scans. A disadvantage is that we can't provide sane emulation of
* READ COMMITTED behavior --- it would be nice if we had some other way to
* control which remote queries share a snapshot.
*/
为了解释这一点,想象一个执行计划如下的查询:
Nested Loop
-> Seq Scan on local_table
-> Foreign Scan on remote_table
在这里,将扫描外表,查找在本表中找到的每一行。所有这些外表上的扫描都在同一个事务中执行,但是如果postgres_fdw使用默认的READ COMMITTED
事务隔离级别,那么并发数据修改可能会导致远程表上的这些查询得到不一致的结果。
由于postgres_fdw使用REPEATABLE READ
(或SERIALIZABLE
,如果这是本地事务隔离级别),总有可能外表上的DML语句得到您所观察到的序列化错误。您无法避免这种情况,但是您可以以正确的方式处理它,即回滚并重试操作,直到操作成功。