この質問STRICT
に答えているときに、単純な SQL 関数を宣言すると、パフォーマンスが低下することに遭遇しました。
デモンストレーションのために、配列の 2 つの要素を昇順で並べ替える関数の 2 つのバリアントを作成しました。
テスト設定
整数の 10000 のランダムなペアを持つテーブル (
CREATE TABLE tbl (arr int[]);
INSERT INTO tbl
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM generate_series(1,10000);
STRICT
修飾子なしの関数:
CREATE OR REPLACE FUNCTION f_sort_array(int[])
RETURNS int[]
LANGUAGE sql IMMUTABLE AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;
修飾子付きの関数STRICT
(それ以外は同一):
CREATE OR REPLACE FUNCTION f_sort_array_strict(int[])
RETURNS int[]
LANGUAGE sql IMMUTABLE STRICT AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;
結果
私はそれぞれ約20回実行し、最高の結果を得ましたEXPLAIN ANALYZE
.
SELECT f_sort_array(arr) FROM tbl; -- Total runtime: 43 ms
SELECT f_sort_array_strict(arr) FROM tbl; -- Total runtime: 103 ms
これらは、Debian Squeeze での Postgres 9.0.5 の結果です。8.4でも同様の結果。
すべての NULL 値を使用したテストでは、両方の関数が同じように実行されます: ~37 ミリ秒。
私はいくつかの調査を行い、興味深い落とし穴を見つけました。SQL 関数STRICT を宣言すると、ほとんどの場合、関数のインライン展開が無効になります。詳細については、PostgreSQL オンライン ジャーナル、pgsql-performance メーリング リスト、またはPostgres Wikiを参照してください。
しかし、これがどのように説明できるかはよくわかりません。関数をインライン化しないと、この単純なシナリオでパフォーマンスが低下しますか? インデックスなし、ディスク読み取りなし、ソートなし。関数をインライン化することによって合理化された、繰り返しの関数呼び出しによるオーバーヘッドでしょうか?
再テスト
同じテスト、同じハードウェア、Postgres 9.1 . さらに大きな違い:
SELECT f_sort_array(arr) FROM tbl; -- Total runtime: 27 ms
SELECT f_sort_array_strict(arr) FROM tbl; -- Total runtime: 107 ms
同じテスト、新しいハードウェア、Postgres 9.6。ギャップはさらに大きくなりますが、次のようになります。
SELECT f_sort_array(arr) FROM tbl; -- Total runtime: 10 ms
SELECT f_sort_array_strict(arr) FROM tbl; -- Total runtime: 60 ms