小编cis*_*cis的帖子

我是否需要在 UPDATE 的 CTE 中显式 FOR UPDATE 锁?

在 Postgres 13 中,我有一个经常更新的表。然而,更新查询相当复杂,并且多次使用相同的值。因此,使用 CTE 似乎是一件非常合乎逻辑的事情。

一个简化的示例如下所示:

WITH my_cte AS (
    SELECT
          my_id,
          CASE WHEN my_value1 > 100 THEN 50 ELSE 10 END AS my_addition     
    FROM my_table      
    WHERE my_id = $1
)
UPDATE my_table
        SET my_value1 = my_table.my_value1 + my_cte.my_addition,
            my_value2 = my_table.my_value2 + my_cte.my_addition
FROM my_cte
WHERE my_table.my_id = my_cte.my_id
Run Code Online (Sandbox Code Playgroud)

现在我想知道:如果在SELECTCTE 和 之间UPDATE,表被另一个查询更新,my_value1从而发生变化,那么当发生这种情况时,were 的计算my_addition就会变得过时且错误,会发生什么UPDATE。会出现这样的情况吗?或者 Postgres 是否自动设置隐式锁?

如果 Postgres 在这里没有魔法,我需要自己处理它:FOR UPDATESELECTCTE 中做就足够了吗?

抱歉,如果我没有在这里说清楚:我并不是想“看到”这些并发修改,我想阻止它们,即一旦计算完成SELECT,没有其他查询可能会修改该行,直到计算UPDATE …

postgresql cte locking update postgresql-13

9
推荐指数
1
解决办法
3747
查看次数

从 Postgres 11 升级到 Postgres 12 使某些查询速度慢了 300 倍,可能是由于新的 CTE 处理

我的应用程序当前使用 PostgreSQL 11.6。今天,我在虚拟机上测试了 PostgreSQL 12.1,结果令人震惊:一个重要查询在版本 11(同一虚拟机)上需要 100 毫秒,现在在 Postgres 12 上只需要大约 36 秒。这慢了 300 多倍。

我怀疑 CTE 的新处理方式,即MATERIALIZED,NOT MATERIALIZED是造成这种情况的原因。

如果我将每个 CTE 更改为MATERIALIZED,查询时间将从 36 秒减少到 6 秒。明显好一些,但仍然比版本 11 慢 50 倍以上。

如果我没猜错的话,在 PostgreSQL 12 中你有两个替代选项:

  • 使用MATERIALIZEDCTE 只执行一次,但你失去了索引的好处
  • 您可以获得NOT MATERIALIZED索引的好处,但每次访问其结果时都会执行您的 CTE。

那是对的吗?

是否有任何技巧,例如返回 Postgres 11 行为的特殊设置?或者是处理此问题的唯一方法,手动评估每个 CTE 是否MATERIALIZED更好NOT MATERIALIZED

我想,很多时候并不清楚哪种方式更好。我的应用程序包含数百个 CTE,其中许多都执行表查询和昂贵的函数调用(文档中的示例,他们说这NOT MATERIALIZED更好)。

编辑: 我检查过的内容以使结果具有可比性:

  • 同一虚拟机
  • 相同且非常小的数据集
  • 相同的 postgresql.conf
  • 重新索引
  • vacuum analyze

结果EXPLAIN ANALYZE …

cte upgrade postgresql-12 postgresql-performance

6
推荐指数
1
解决办法
5446
查看次数

基于函数值的递归 CTE 在 Postgres 12 上明显慢于 11

跟进我关于 Postgres 12 中的某些查询比 11 中的查询慢的问题,我认为我能够缩小问题的范围。似乎基于函数值的递归 CTE 是有问题的地方。

我能够分离出一个相当小的 SQL 查询,它在 Postgres 12.1 上运行的时间比在 Postgres 11.6 上运行的时间要长得多,例如 Postgres 12.1 中的大约 150 毫秒与 Postgres 11.6 中的大约 4 毫秒。我能够在各种系统上重现这种现象:在 VirtualBox 中的多个 VM 上;通过两台不同物理机器上的 Docker。(有关 docker 命令,请参阅附录)。然而,奇怪的是,我无法在https://www.db-fiddle.com/上重现它(在那里看不到区别,两者都很快)。

现在进行查询。首先,我们创建这个简单的函数

CREATE OR REPLACE FUNCTION public.my_test_function()
 RETURNS SETOF record
 LANGUAGE sql
 IMMUTABLE SECURITY DEFINER
AS $function$ 

SELECT 
        1::integer AS id,
        '2019-11-20'::date AS "startDate",
        '2020-01-01'::date AS "endDate"

$function$;
Run Code Online (Sandbox Code Playgroud)

然后对于实际查询

WITH  "somePeriods" AS  (
      SELECT * FROM my_test_function() AS 
      f(id integer, "startDate" date, "endDate" …
Run Code Online (Sandbox Code Playgroud)

postgresql cte recursive postgresql-12 postgresql-performance

5
推荐指数
1
解决办法
1639
查看次数