intaggモジュールは整数型の集約子と列挙子を提供します。
集約子は、正確に提供する整数のみを含む整数型配列を生成するint_array_aggregate(integer)
集約関数です。
以下にまったく役に立たない例を示します。
test=# select int_array_aggregate(i) from test-# generate_series(1,10,2) i; int_array_aggregate --------------------- {1,3,5,7,9} (1 row)
列挙子は、setof integerを返すint_array_enum(integer[])
関数です。
これは基本的に上記集約子の反対の操作を行います。
指定された整数型配列を行集合に拡張します。
以下に例を示します。
test=# select * from int_array_enum(array[1,3,5,7,9]); int_array_enum ---------------- 1 3 5 7 9 (5 rows)
多くのデータベースシステムは1対多のテーブルを持ちます。 以下のようにこうしたテーブルは通常、2つのインデックス用のテーブル間に存在します。
CREATE TABLE left (id INT PRIMARY KEY, ...); CREATE TABLE right (id INT PRIMARY KEY, ...); CREATE TABLE one_to_many(left INT REFERENCES left, right INT REFERENCES right);
通常以下のように使用されます。
SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right) WHERE one_to_many.left = item;
これは、左辺のテーブル内にある項目に対応した、右辺のテーブル内のすべての項目を返します。 これはSQLで非常によく使用される式です。
さて、この方法論はone_to_manyテーブル内に非常に多数の項目がある場合に扱いにくくなり得ます。 しばしばこうした結合は、インデックススキャンと特定された左辺の項目に対応した右辺のテーブル内の項目をそれぞれ取り出すことになります。 非常に動的なシステムでは、十分に行うことができません。 しかし、ほぼ静的なデータが一部にある場合、集約子を使用してようやくテーブルを作成することができます。
CREATE TABLE summary as SELECT left, int_array_aggregate(right) AS right FROM one_to_many GROUP BY left;
これは左辺項目毎に1行を持ち、右辺の項目の配列をもつテーブルを作成します。 さて、これは配列を使用する何らかの方法がないとかなり使い勝手が悪くなります。 これが配列列挙子が存在する理由です。 以下を行うことができます。
SELECT left, int_array_enum(right) FROM summary WHERE left = item;
上のint_array_enum
を使用した問い合わせは、以下と同じ結果を生成します。
SELECT left, right FROM one_to_many WHERE left = item;
違いは、ようやくテーブルに対する問い合わせはテーブルから1行だけを取り出す必要があるのに対し、直接one_to_manyに問い合わせる場合はインデックススキャンと各項目に対し行を取り出さなければならないという点です。
あるシステムでEXPLAINを行うと8488というコストを持つ問い合わせが329というコストまで減少しました。 元の問い合わせはone_to_manyテーブルを含む結合でしたが、以下のように置き換えられました。
SELECT right, count(right) FROM ( SELECT left, int_array_enum(right) AS right FROM summary JOIN (SELECT left FROM left_table WHERE left = item) AS lefts ON (summary.left = lefts.left) ) AS list GROUP BY right ORDER BY count DESC;