2017-03-14 4 views
0

私は非常に単純なplpgsql関数を書いています。これは25mlnの行テーブルから各行を取り出し、前の行と比較します。 2つの兄弟行に等しい場合は、"AOGUID"列が返されます。私はそれを理解したようなぜFOR <query> LOOPは基本クエリよりもはるかに遅いですか?

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" 

残念ながら、プレーンクエリ時間に近い時間で実行する必要があります。プレーンクエリは1時間で実行されますが、関数は80時間で実行されます。

plpgsql関数がプレーンなクエリよりもずっと遅く実行される理由と、パフォーマンスをどのように向上させることができるのかを誰でも説明できますか?

PS:

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

Zemla " (コスト= 0.56..3336281.02行= 25852488幅= 37) "" インデックスのみにzemla_aoguid_not_uniqueを使用してスキャンする"

+1

- なぜウィンドウ関数を使用しないのですか? –

+3

プレーンSQLで行うことができれば、forループ(またはPL/pgSQL)を使用しないでください。 –

+0

@a_horse_with_no_name:[決して言わないでください](http://dba.stackexchange.com/questions/166374/grouping-or-window/166397#166397)この経験則には例外があります。 –

答えて

0

コストをチェックそのような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

+0

このqryは50〜70倍高速です。もっと改善できますか?私は "FILTERR" '' ' についてのあなたの答えを理解していない以上( SELECT "AOGUID" から "AOGUID"、ラグ( "AOGUID")( "AOGUID" BY ORDER)= FROM "AOGUID" test_eq を選択"Zemla" )eq ここで、test_eq ' – alexey2baranov

+0

はそうは思わない - あなたはまだ比較を行う必要があります。私はpostgresのバージョンを知らなかったので、9.4付属の機能についてコメントを付けました –

+0

私は9.5 'CTE Scan on pre94(費用= 5311965.00..5838177)を使用しています。82行= 13155320幅= 516) " フィルタ:test_eq" CTEのpre94" - > WindowAgg(コスト= 4785752.18..5311965.00行= 26310641幅= 37)」 - >ソート(コスト= 4785752.18..4851528.78行= "ZEMLA" "AOGUID" " - >" Zemla "でSeqスキャン(コスト= 0.00..823646.41行= 26310641幅= 37)' – alexey2baranov

1

を使用する場合も、あなたはFILTERでQRY減らすことができますたぶん私はあなたのクエリを誤読していますが、あなたは一度だけ「Zemla」でより多く表示されるすべてのAOGUIDエントリを特定していませんか?グループ化された単一のクエリとして実行できませんか?

SELECT "AOGUID" FROM "Zemla" 
GROUP BY "AOGUID" 
HAVING COUNT(*) > 1 
ORDER BY "AOGUID" 
関連する問題