テーブルに対してフィルター処理される任意の数のパラメーターをユーザーが指定できる場合があります。簡単に言えば、それぞれ 64 個のバケットを持つ一連のパラメーターがあります。全体として、これは数値の線形シーケンスを表します。各レコードには、任意の数のバケット ポイントが含まれます。
さらに、これらの数は各バケット内の範囲内にあります。
ユーザーは、任意の数の任意のレコードの目的の値の範囲を指定できます。指定されたすべてのパラメーター (バケット) が重複しているレコードが返されます。
安値と高値があることに気付くでしょう。これが範囲です。どちらかが重複しているかどうかを確認することで、範囲クエリを使用するよりもはるかに高速に結果を得ることができます。これは最適化手法です。
次に、2 つの条件の例を示します。
SELECT id
FROM mytable2
WHERE (val_low && (ARRAY(SELECT generate_series((0 * 64) + 20, (0 * 64) + 28))) OR
val_high && (ARRAY(SELECT generate_series((0 * 64) + 20, (0 * 64) + 28))))
AND (val_low && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15))) OR
val_high && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15))))
val_low
およびval_high
バケットは、指定された範囲の配列との交差についてテストされます。
問題は、このクエリを関数で動的に作成する必要があることです。パラメーター リストは関数に (ユーザー定義型 [配列] として) 渡され、クエリが動的に生成されてから実行されます。
それは機能しますが、関数に SQL を記述しなくてもこれを実行できるようにしたいと考えています。
具体的には、次のように関数にカスタム型配列が渡されます。
param_num int,
val_low int,
val_high int
generate_series 関数呼び出しの値は(param_num * 64) + val_low, (param_num * 64) + val_high
.
これは可能ですか?
サンプルデータの作成:
DROP TABLE IF EXISTS
mytable2;
CREATE TABLE
mytable2
(
id INT NOT NULL PRIMARY KEY,
val_low int[],
val_high int[]
);
SELECT SETSEED(0.20130725);
WITH t AS
(
SELECT id,
1 + FLOOR(RANDOM() * 24) AS l1, (RANDOM() * 8)::int AS h1,
1 + FLOOR(RANDOM() * 24) AS l2, (RANDOM() * 8)::int AS h2,
1 + FLOOR(RANDOM() * 24) AS l3, (RANDOM() * 8)::int AS h3,
1 + FLOOR(RANDOM() * 24) AS l4, (RANDOM() * 8)::int AS h4
FROM generate_series(1, 500000) id
)
INSERT
INTO mytable2
SELECT T.id, array[t.l1, (1 * 64) + t.l2, (2 * 64) + t.l3, (3 * 64) + t.l4],
array[t.l1 + t.h1, (1 * 64) + t.l2 + t.h2, (2 * 64) + t.l3 + t.h3,
(3 * 64) + t.l4 + t.h4]
FROM T;
CREATE INDEX
ix_mytable2_vhstore_low
ON mytable2
USING GIN (val_low);
CREATE INDEX
ix_mytable2_vhstore_high
ON mytable2
USING GIN (val_high);
サンプルクエリ:
--EXPLAIN ANALYZE
SELECT COUNT(1)
FROM
(
SELECT id
FROM mytable2
WHERE (val_low && (ARRAY(SELECT generate_series(20, 28))) OR val_high &&
(ARRAY(SELECT generate_series(20, 28))))
AND (val_low && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15)))
OR val_high && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15))))
) m;
結果: 54983