我正在运行以下功能。使用更小的表进行测试可以按预期工作(18行 - 约400毫秒)。但是,当指向我的真实数据(315000行)时,它运行48小时仍然继续。这比我预期的线性外推要长得多。
有没有办法优化以下功能?
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$;
答案 0 :(得分:4)
@kordirko明确表示您的DO
声明不必要地昂贵。但还有更多。
更新中的概率分布不均匀:
'variable1'
。(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添加到结果中毫无意义。而是与4
和5
而不是5
和6
(或3
和1
进行比较 - 这里没有区别。)
与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
比较这个相关答案的最后一章:
只有最后一个变体需要NOT NULL
上的索引才能快。应该由主键约束覆盖。
答案 1 :(得分:1)
尝试简单的更新:
UPDATE tablex
SET test = CASE trunc(random() * 6) + 1
WHEN 5 THEN 'variable1'
WHEN 6 THEN 'variable2'
ELSE test
END
;
我想它至少会快50到200倍。