UPDATE 查询需要很长时间 PostgreSQL

Posted

技术标签:

【中文标题】UPDATE 查询需要很长时间 PostgreSQL【英文标题】:UPDATE Query takes very long PostgreSQL 【发布时间】:2017-01-18 09:44:35 【问题描述】:

我想UPDATEmyTable 表中的几行(335379 行)。

CREATE OR REPLACE FUNCTION costs_f(
someFloat float) RETURNS void AS
$$
BEGIN
UPDATE ways 
SET cost_time = CASE WHEN $1 = -1.0 THEN -1 ELSE anotherFloat * $1 END
FROM (SELECT w.gid AS id,
mc.name,
w.someCosts
FROM myTable mt
JOIN myClasses mc
ON mt.class_id = mc.class_id) AS tempTable
WHERE gid = id AND tempTable.name_name = $2;
END
$$
language 'plpgsql';

然后在另一个函数中调用这个函数

CREATE OR REPLACE FUNCTION update_costs_f(
someFloat float) RETURNS void AS
$$
DECLARE
someArr varchar[] := ARRAY['a', 'b', 'c', 'd',
    'e', 'f', 'g', 'h', 'i', 
    'j', 'k', 'l',
    'm', 'n', 'o', 'p', 
    'q', 'r', 's', 't', 'ul', 'v'];
i text;
BEGIN
FOREACH i IN ARRAY someArr LOOP
    PERFORM costs_f($1, i);
END LOOP;
END
$$
language 'plpgsql';

那我做

SELECT update_costs_f(10.0);

但是,这需要很长时间! 有没有办法提高速度?

*注意:此代码是抽象的。在第二个函数中有更多的ForEach 循环。我有几个数组。

【问题讨论】:

您对代码进行了模糊处理,以至于它不再有效。您正在循环内将字符串传递给costs_f(),但该函数需要一个浮点值。该函数还使用未在任何地方声明的变量anotherfloat。而且,不相关但是:比较浮点数是否相等可能会产生许多令人惊讶的结果:floating-point-gui.de 它仍然无效 - 但给出的示例可以简化为单个更新语句并且不需要函数。所以你的抽象没有帮助。 @a_horse_with_no_name 当然我可以把它写成一个语句。但是这些函数在程序不同部分的不同位置被调用。所以我需要它们具有两种不同的功能。我感兴趣的是,当我以执行函数的方式执行更新时,为什么更新需要这么长时间。 因为您正在进行缓慢的逐行更新。更新多行的单个语句总是比更新单行的多个语句更快。改善这一点的唯一方法是摆脱缓慢、低效和不可扩展的逐行处理 @a_horse_with_no_name 啊,谢谢。你能告诉我要找什么吗? 【参考方案1】:

1。摆脱 tempTable.name_name = $2;

正如@a_horse_with_no_name 所说,您不应该运行多个更新语句。

我看到您为someArr 中的每个字母多次调用PERFORM costs_f($1, i)。不要多次调用它,而是调用一次并使用in 运算符,例如:

AND tempTable.name_name in($2);

2。将更新拆分为 2 个语句

你应该把你的更新语句分成两个语句:

UPDATE ways 
SET cost_time = -1.0 FROM tempTable 
WHERE gid = id AND tempTable.name_name = $2 AND
$1 = -1.0 ;

UPDATE ways 
SET cost_time =anotherFloat * $1 FROM tempTable 
WHERE gid = id AND tempTable.name_name = $2 AND
NOT ($1 = -1.0) ;

注意:通过仅使用 tempTable 而不是完整嵌套的 subuery/alias 来简化

3。将条件移动到嵌套的 Aliased From SubQuery

​​>

马上我可以看到您可以将条件name_name = $2 直接移动到from aliased subquery

FROM (SELECT w.gid AS id,
mc.name,
w.someCosts
FROM myTable mt
JOIN myClasses mc
ON mt.class_id = mc.class_id 
WHERE name_name = $2 ) AS tempTable
WHERE gid = id;

齐心协力

CREATE OR REPLACE FUNCTION update_costs_f(
someFloat float) RETURNS void AS
$$
DECLARE
someArr varchar[] := ARRAY['a', 'b', 'c', 'd',
    'e', 'f', 'g', 'h', 'i', 
    'j', 'k', 'l',
    'm', 'n', 'o', 'p', 
    'q', 'r', 's', 't', 'ul', 'v'];
i text;
BEGIN
PERFORM costs_f($1, someArr );
END
$$
language 'plpgsql';


CREATE OR REPLACE FUNCTION costs_f(
someFloat float) RETURNS void AS
$$
BEGIN
UPDATE ways 
SET cost_time = -1.0
FROM (SELECT w.gid AS id,
mc.name,
w.someCosts
FROM myTable mt
JOIN myClasses mc
ON mt.class_id = mc.class_id
WHERE $1 = -1.0 AND gid = id AND tempTable.name_name = ANY($2);
) AS tempTable;    

UPDATE ways 
SET cost_time =anotherFloat * $1 
FROM (SELECT w.gid AS id,
mc.name,
w.someCosts
FROM myTable mt
JOIN myClasses mc
ON mt.class_id = mc.class_id
WHERE NOT($1 = -1.0) AND gid = id AND tempTable.name_name =ANY($2);
) AS tempTable;

END
$$
language 'plpgsql';

终于

您可以使用 IF 语句来避免同时运行两个 SQL 更新语句...

见:PostgreSQL IF statement 示例:

IF ($1 = -1.0) THEN
   ...
ELSE 
  ...
END IF;

【讨论】:

谢谢。您在costs_f 中缺少函数参数。调用它时,(PERFORM costs_f($1, someArr ); 你的传递 $1someArr 但你没有在这里定义它CREATE OR REPLACE FUNCTION costs_f( someFloat float) RETURNS void AS @Stophface Yeh...但是您是否尝试过更改以检查速度? 我正在尝试实施。它嘲笑阵列。我更改了CREATE OR REPLACE FUNCTION costs_f( someFloat float someText text[]) RETURNS void ASSELECT PERFORM costs_f($1, someArr::text[]); 但它说ERROR: operator does not exist: text = text[] LINE 10: WHERE $1 = -1.0 AND gid = id AND tempTable.name_name in ($2) HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. 而错误消息中花哨的^ 指向IN @Stophface dbrnd.com/2015/09/string-array-input-parameter-in-postgresql ? ArrayText character varying[] 。也尝试用 ANY 函数代替 IN。 ***.com/q/30298031/1688441 ... ANY(ArrayText) 我第一次尝试过。我更改为CREATE OR REPLACE FUNCTION costs_f( someFloat float someText character varying[]) 和类型转换以及:: character varying[]。同样的错误。与varchar[] 的结果相同。我已经尝试将IN 更改为ANYERROR: syntax error at or near "ANY" text = text[] LINE 10: WHERE $1 = -1.0 ANY gid = id AND

以上是关于UPDATE 查询需要很长时间 PostgreSQL的主要内容,如果未能解决你的问题,请参考以下文章

cocoapods:pod update 和 pod install 需要很长时间

PostgreSQL SELECT ... FOR UPDATE:并发长时间运行的查询会发生啥?

BigQuery 查询需要很长时间

查询需要很长时间

MySQL 查询返回 JSON 数据需要很长时间

Linq 更新需要很长时间来处理