读取由 postgresql 函数创建的未提交行?

Read uncommited rows created by postgresql function?

我编写了一个函数,根据参数和 returns 创建行的 ID 在 table mytable 中创建一行。

不幸的是,如果我使用下面的语句,SELECT returns 没有行,好像函数的事务不同于SELECT.

SELECT * FROM mytable WHERE id = createComplexRow(...);

我的理解是 运行 select 和函数的同一个事务,然后应该能够读取未提交的行。

我正在尝试使用 postgres 9.6

知道如何让它正常工作吗?

让我们看看是怎么回事。

CREATE TABLE mytable(
   id serial PRIMARY KEY,
   val timestamp with time zone NOT NULL
);

CREATE FUNCTION createcomplexrow() RETURNS integer
   LANGUAGE SQL AS
'INSERT INTO mytable (val) VALUES (current_timestamp) RETURNING id';

该函数是隐式的 VOLATILE,因为它必须如此,因为它修改了数据库。

让我们插入几行:

SELECT createcomplexrow();
SELECT createcomplexrow();

现在让我们试试你的说法:

SELECT * FROM mytable WHERE id = createcomplexrow();

 id | val
----+-----
(0 rows)

确实,没有结果!

但是table中有新的值:

SELECT * FROM mytable;

 id |              val
----+-------------------------------
  1 | 2017-07-18 11:50:22.031922+02
  2 | 2017-07-18 11:50:23.640775+02
  3 | 2017-07-18 11:50:31.392773+02
  4 | 2017-07-18 11:50:31.392773+02
(4 rows)

要查看会发生什么,EXPLAIN 查询:

EXPLAIN (COSTS off)
   SELECT * FROM mytable WHERE id = createcomplexrow();

             QUERY PLAN
-------------------------------------
 Seq Scan on mytable
   Filter: (id = createcomplexrow())
(2 rows)

PostgreSQL 扫描 table,对于找到的每一行,它调用函数并将结果与​​该行的 id 进行比较。

当它扫描带有id = 1的行时,该函数将return 3(并插入一行)。因此跳过 id = 1 的行。

类似地,id = 2 的行被跳过,并创建一个新的 id = 4 的行。

现在为什么执行停止在这里而不是继续扫描两个新创建的行?

这些lines from the documentation稍微解释一下:

In effect, a SELECT query sees a snapshot of the database as of the instant the query begins to run. However, SELECT does see the effects of previous updates executed within its own transaction, even though they are not yet committed.

(强调我的)

该语句看不到该函数的效果,因为该函数不是在之前的更新中执行的,而是在相同的语句[=63]中执行的=] 作为 SELECT.

(同样发生在 data modifying WITH queries 中;您可能会发现阅读该部分文档很有启发性。)

实际上,您应该很高兴以这种方式处理它,否则您将陷入无限循环,继续向 table.

中插入行