web-dev-qa-db-ja.com

PostgreSQLの生のクエリと「関数がTABLEを返す」-パフォーマンスの異常な違い。どうして?

私はPostgreSQLを使用しており、レポートに使用されます。現在の構成方法は次のとおりです。

次のように、レポートデータを返す複雑なクエリがあります。

select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;

このクエリを利用する関数があり、そのように定義されています

CREATE OR REPLACE FUNCTION GetMyReport(IN fromdate timestamp without time zone, IN todate timestamp without time zone)
  RETURNS TABLE(Name1 character varying, Name2 character varying) AS
$BODY$

--query start
select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;
--query end

$BODY$
  LANGUAGE sql VOLATILE
  COST 10
  ROWS 1000;

最後に、レポートアプリケーションが関数を呼び出すと、次のSQLが送信されます。

select null::text as Name1, Name2 from GetMyReport ('2012-05-28T12:19:39.0000000+11:00'::timestamp, '2012-05-28T12:19:44.0000000+11:00'::timestamp);

そして私の問題は:

  • データベースに対して「クエリ」だけを実行すると、非常に高速に実行されます。実際、返されるデータが適度に小さい場合、ほんの数秒で
  • レポートアプリケーションから渡されたSQLを実行すると、実行に非常に時間がかかります-毎回。実際、クエリによって数秒で返される同じデータに対して10分以上。
  • 実際、私は生のクエリを実行し、ミリ秒かかり、関数を実行します-約10分かかり、クエリを再度実行します-ミリ秒、関数を実行します-もう一度10分、すべてまったく同じパラメーターを使用します。

その理由は何でしょうか?

5
Evgeny

OK、それは簡単でした。データベースがパラメータを認識する前にクエリプランを準備する必要があることが判明しました。これは悪い結果につながります。解決策は、plpgsqlを使用してQUERYEXECUTEを返すことでした。これで、パフォーマンスは予想通り同じです。

CREATE OR REPLACE FUNCTION GetMyReport(IN fromdate timestamp without time zone, IN todate timestamp without time zone)
  RETURNS TABLE(Name1 character varying, Name2 character varying) AS
$BODY$

BEGIN
RETURN QUERY EXECUTE'
select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;' USING $1, $2
END

$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 10
  ROWS 1000;
4
Evgeny