Postgres功能优化

时间:2015-03-28 21:46:46

标签: performance postgresql random sql-update plpgsql

我正在运行以下功能。使用更小的表进行测试可以按预期工作(18行 - 约400毫秒)。但是,当指向我的真实数据(315000行)时,它运行48小时仍然继续。这比我预期的线性外推要长得多。

  1. 有更好的方法吗?
  2. 有没有办法测试它是否正在执行它仍在运行时应该做什么?
  3. 有没有办法优化以下功能?

    DO 
    $do$ 
    DECLARE r public.tablex%rowtype; 
    BEGIN 
    FOR r IN SELECT id FROM public.tablex 
    LOOP 
    IF (select cast((select trunc(random() * 6 + 1)) as integer) = 5) THEN 
    UPDATE public.tablex SET test='variable1' WHERE id = r.id; 
    ELSIF (select cast((select trunc(random() * 6 + 1)) as integer) = 6) THEN 
    UPDATE public.tablex SET test='variable2' WHERE id = r.id; 
    END IF; 
    END LOOP; 
    RETURN; 
    END 
    $do$;
    

2 个答案:

答案 0 :(得分:4)

@kordirko明确表示您的DO声明不必要地昂贵。但还有更多。

概率

更新中的概率分布不均匀:

  • 1/6或所有行都更新为'variable1'
  • 但只有5/36((1/6) * (5/6))更新为'variable2'

根据您的其余代码判断,我将假设这是一个意外错误,您希望每个 等于1/6的份额。

消毒

您可以简化为:

UPDATE tablex
SET    test = CASE trunc(random() * 6)
                 WHEN  float '4' THEN 'variable1'
                 WHEN  float '5' THEN 'variable2'
                 ELSE  test
              END;
  • 将1添加到结果中毫无意义。而是与45而不是56(或31进行比较 - 这里没有区别。)

  • double precision(= float)常量进行比较,而不是将表达式double precision的{​​{1}}结果转换为{{}}每行{1}},就像在原始代码中一样。

更好,但 仍然非常低效

高级

trunc(random() * 6)

100%等效(除非您有触发器integer或某些奇特的设置)但更快,因为只触及实际接收更新的行。三分之二的行根本没有触及。

  • 请注意,这两个UPDATE tablex SET test = CASE WHEN random() >= float '0.5' THEN 'variable1' ELSE 'variable2' END WHERE random() >= float '0.6666667'; 来电完全独立。

  • 如果您希望尽可能精确地了解三分之二的概率,请使用ON UPDATE代替random()。但这确实是学术上的差异。

  • 在运行此命令(在同一事务中)之前,您可能需要2 / float '3.0'以排除具有并发写入的竞争条件。 Details in the manual.

替代

如果,则列float '0.6666667'已经可以保留其中一个目标值' variable1'或者'变量2' (在少数情况下)这更便宜,但是:

LOCK tablex IN ROW EXCLUSIVE MODE

避免更多空更新 如果定义test UPDATE tablex t SET test = upd.val FROM ( SELECT id, CASE WHEN random() >= float '0.5' THEN 'variable1' ELSE 'variable2' END AS val FROM tablex WHERE random() >= float '0.6666667' -- ORDER BY id -- the last two lines only to defend against ... -- FOR UPDATE -- ... concurrent writes and possible deadlocks ) upd WHERE t.id = upd.id AND t.test IS DISTINCT FROM upd.val; ,您可以简化为:

test

比较这个相关答案的最后一章:

答案 1 :(得分:1)

尝试简单的更新:

UPDATE tablex
SET  test =  CASE trunc(random() * 6) + 1
                 WHEN  5 THEN 'variable1'
                 WHEN  6 THEN 'variable2'
                 ELSE test
       END
;

我想它至少会快50到200倍。