哪个更新数千个表行更快?

Gei*_*ist 2 postgresql performance stored-procedures update postgresql-10

使用PostgreSQL v10.1.2 中的存储过程,哪种方法最快或哪种更好:检查行是否存在然后更新或尝试直接更新,但可能找不到与条件匹配的行?我需要检查很多条件相同的表,表是不是“非规范化”,我进行了几次测试,有时选项 1在其他情况下更快,选项 2 ...

选项1:

IF EXISTS ( SELECT  1
FROM   public.table1 
WHERE  column1 = 'oldvalue' )
THEN
   UPDATE public.table1
   SET   column1 = 'newvalue' , date_update= .... 
   WHERE  column1 = 'oldvalue';
END IF ;
Run Code Online (Sandbox Code Playgroud)

选项 2:

UPDATE public.table1
SET   column1 = 'newvalue' , date_update= ... 
WHERE  column1 = 'oldvalue';
Run Code Online (Sandbox Code Playgroud)

选项 3:

perform FROM   public.table1 WHERE  column1 = 'oldvalue' ;
if found then 
   UPDATE public.table1 SET column1='newvalue', date_update = ... WHERE column1 = 'oldvalue';
end if ;
Run Code Online (Sandbox Code Playgroud)

我做了:

BEGIN;
EXPLAIN ANALYZE VERBOSE select a_test_w_perform();
ROLLBACK;
Run Code Online (Sandbox Code Playgroud)

对于每个选项,时间平均值各不相同,时间结果类似于:

Erw*_*ter 5

这是普遍较快只是尝试UPDATE

发出SELECT第一个,只会增加读取成本。另外,更重要的是,无论如何,它在并发写入数据库的情况下是不可靠的。您必须添加FOR UPDATE或类似锁定行。但是不要。只需发出UPDATE.

不过,在许多情况下提高性能的一种方法是:避免空更新:

UPDATE public.table1
SET    column1 = 'newvalue'
     , date_update = ... 
WHERE  column1 = 'oldvalue'
AND   (column1   , date_update) IS DISTINCT FROM 
      ('newvalue', ...        );  -- to skip empty updates
Run Code Online (Sandbox Code Playgroud)

有关的:

SELECT如果您想参与LIMIT(或类似),首先发出是有意义的,这是不允许UPDATE直接进入的。但考虑并发:

产生的性能可能因许多参数而异。热缓存、并发事务、服务器负载等。您的情况可能特别棘手:

检查许多具有相同条件的表

涉及大量表使得很难找到最佳查询计划。如果你知道某个谓词是特别有选择性的——而 Postgres 没有——那么首先运行一个便宜的、简化的可能是值得的SELECT。但是你需要正确处理并发。

一般来说,这表示您的查询或有关费用设置或统计服务器配置的问题,这将是更好地修复不是解决该问题。但是Postgres的确有一些盲点,就像没有合并多个条件统计或统计信息嵌套值文档类型一样jsonbxml等等。

更新: Postges 10 添加了“多列优化器统计信息来计算相关率和不同值的数量”。(对于嵌套在文档类型中的值仍然没有帮助。)手册中的详细信息。

更新整个表的大部分时,可能需要不同的策略: