【问题标题】:Why is FOR <query> LOOP is so much slower than basic query?为什么 FOR <query> LOOP 比基本查询慢得多?
【发布时间】:2017-03-14 11:18:31
【问题描述】:

我编写了非常简单的 plpgsql 函数,它从 2500 万行表中获取每一行并与上一行进行比较。如果两个同级行具有相等的"AOGUID" 列,则返回它们。

CREATE or replace FUNCTION get_duplicate_zemli() RETURNS setof character varying AS $$
DECLARE
    each_zemla character varying;
    prev_zemla character varying;
BEGIN
    FOR each_zemla IN SELECT "AOGUID" FROM "Zemla" ORDER BY "AOGUID" LOOP
        if (prev_zemla = each_zemla) then
            return next each_zemla;
        end if;
        prev_zemla:= each_zemla;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

据我了解,这个函数应该在接近普通查询时间的时候执行

SELECT "AOGUID" FROM "Zemla" ORDER BY "AOGUID" 

不幸的是,这不是真的。普通查询在一小时内执行,而函数在 80 小时内执行!

谁能解释一下为什么 plpgsql 函数的执行速度比普通查询慢得多,以及如何提高性能?

PS:

explain SELECT "AOGUID" FROM "Zemla" ORDER BY "AOGUID" 

“在“Zemla”上使用 zemla_aoguid_not_unique 进行仅索引扫描 (成本=0.56..3336281.02 行=25852488 宽度=37)"

【问题讨论】:

  • 不相关,但是 - 为什么不使用窗口函数?例如laglead ?...
  • 如果你可以使用纯 SQL 的话,永远不要使用 for 循环(或 PL/pgSQL)。
  • @a_horse_with_no_name: Never say never. 这个经验法则有例外。
  • 有多种方法可以使这个(很多)更快。最佳答案取决于 [postgresql-performance] 问题的基本信息。请考虑instructions in the tag info. 最重要的是:您的Postgres 版本以及"AOGUID" 中有多少不同的值。 edit 问题中的所有定义信息,不要将其隐藏在 cmets 中。除此之外,basic 的 80 倍执行时间很奇怪。
  • 您是要提供更多信息还是这个问题已经完成?

标签: performance postgresql plpgsql postgresql-performance


【解决方案1】:

也许我误读了您的查询,但您不只是识别在“Zemla”中多次出现的任何 AOGUID 条目吗?这不能作为单个分组查询来完成吗?

SELECT "AOGUID" FROM "Zemla"
GROUP BY "AOGUID"
HAVING COUNT(*) > 1
ORDER BY "AOGUID"

【讨论】:

    【解决方案2】:

    检查此类 qry 的成本:

    explain with pre94 as (
      SELECT "AOGUID", lag("AOGUID") over (ORDER BY "AOGUID") = "AOGUID" test_eq FROM "Zemla"
    ) 
    select "AOGUID" from pre94 where test_eq
    

    我相信窗口函数可以比自创函数更好地帮助您完成任务。

    如果你使用9.4 or later,你也可以用FILTER减少qry

    【讨论】:

    • 这个 qry 快 50-70 倍。你能再改进一下吗?我不明白你关于“FILTERR”的回答``` select “AOGUID” from (SELECT "AOGUID", lag("AOGUID") over (ORDER BY "AOGUID") = "AOGUID" test_eq FROM "Zemla")eq where test_eq `
    • 不这么认为——你仍然需要进行比较。我不知道你的 postgres 版本,所以我对 9.4 附带的功能发表了评论
    • 我正在使用 9.5 CTE Scan on pre94 (cost=5311965.00..5838177.82 rows=13155320 width=516)" Filter: test_eq" CTE pre94" -&gt; WindowAgg (cost=4785752.18..5311965.00 rows=26310641 width=37)" -&gt; Sort (cost=4785752.18..4851528.78 rows=26310641 width=37)" Sort Key: "Zemla"."AOGUID"" -&gt; Seq Scan on "Zemla" (cost=0.00..823646.41 rows=26310641 width=37)
    猜你喜欢
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 2021-10-29
    相关资源
    最近更新 更多