私のデータベース設計では、多くの機能が使用されています。そしてそれらの多くは非常に遅いです。だから、実行を少し速くするためにインデックスの一部を作成することは賢明な考えであると判断しました。 しかし、PostgreSQL(9.6)が実際に私のインデックスを使用するように説得することはできません。Postgresは低速機能のインデックスを使用しません
この表「ユーザー」が多い
id integer | name jsonb
1 | {"last_names": ["Tester"], "first_names": ["Teddy","Eddy"]}
2 | {"last_names": ["Miller"], "first_names": ["Lisa","Emma"]}
を考えてみましょう、私は1つの文字列として名前を必要とするが、それは私が置くことを決めた
SELECT array_to_string(jsonb_arr2text_arr(name->'last_names'), ' ') || ', ' || array_to_string(jsonb_arr2text_arr(name->'first_names'), ' ');
(いわゆる「concat_name」)のようなクエリで行われています複数のテーブルで使用されているため、その機能を関数に組み込むことができます。
CREATE OR REPLACE FUNCTION public.concat_name(name jsonb)
RETURNS text AS
$BODY$
SELECT pg_sleep(50);
SELECT array_to_string(jsonb_arr2text_arr(name->'last_names'), ' ') || ', ' || array_to_string(jsonb_arr2text_arr(name->'first_names'), ' ');
$BODY$
LANGUAGE sql IMMUTABLE SECURITY DEFINER
COST 100;
実際にテストするにはそれが動作するかどうか、私は "人工的に"タイムアウトを追加しました。成功すると(理由pg_sleepの)期待される時間を要する
CREATE INDEX user_concat_name_idx ON "user" (concat_name(name));
: は今、私のようなインデックスを作成しました。クエリを実行します。
SELECT concat_name(name) FROM "user";
ただし、インデックスが使用されていないため、クエリが非常に遅いです。代わりに、EXPLAIN
は、プレーナーが「ユーザー」のシーケンススキャンを実行すると伝えます。
私は少しの研究を行いました。多くの人は、テーブルが小さいか、または検索されるデータセットが(ほぼ)テーブル全体であるとクエリプランナーが考えると、シーケンススキャンを行うほうがインデックスを参照してください。 しかし、機能の場合、特に遅いものの場合、それは私には意味をなさない。たとえ1つの行しか含まないテーブルをクエリしても、関数インデックスを使用すると、クエリに毎回50秒かかる関数が含まれていると実行時間が大幅に短縮される可能性があります。
私の意見では、クエリプランナーは、索引付けされた値をルックアップするのに要する時間と、関数を実行するのに要する時間とを比較する必要があります。テーブルまたはクエリ自体(返される行の数)のサイズは、ここでは問題ありません。関数が実行に50秒かかる場合は、インデックスを参照すると常に勝つ必要があります。
だから、毎回関数を実行するのではなく、クエリプレーナがインデックスを使用するようにするにはどうすればよいですか?
最初の点は、発行されたコピー&ペーストであり、動作しなかった実験的なインデックスをコピーしたものです。それを修正しました。 – cis
提案された変更されたconcat_name関数がそのように機能しません。期待される戻り値は「Tester、Teddy Eddy」です。つまりすべての姓+カンマ+すべての姓です。あなたの関数は "Tester、Teddy、Eddy"、すなわちカンマをファーストネームの間に返します。 – cis
あなたはそうです、機能が更新されました。 – klin