インデックス対応

概要

PostgreSQLは何種類かのインデックス形式に対応しており、デフォルトで選択されるB-treeインデックスは特定の値を持つレコードを高速に検索する事が可能です。これ以外にも、Hash、BRIN、GiST、GINなど特性の異なるインデックス形式が提供されており、現在のところPG-StromはBRINインデックスにのみ対応しています。

BRINインデックスは、時系列データにおけるタイムスタンプ値など、物理的に近傍に位置するレコード同士が近しい値を持っている事が期待できるデータセットに対して有効に作用します。本来は全件スキャンが必要な操作であっても、明らかに条件句にマッチしない領域を読み飛ばし、全件スキャンに伴うI/O量を削減する事が可能です。

PG-StromにおいてもBRINインデックスの特性を活用し、GPUにロードすべきデータブロックのうち明らかに不要であるものを読み飛ばす事が可能になっています。

BRIN-index Ovewview

設定

BRINインデックスを利用するために特別な設定は必要ありません。

CREATE INDEX構文を用いて対象列にインデックスが設定されており、かつ、検索条件がBRINインデックスに適合するものであれば自動的に適用されます。

BRINインデックス自体の説明は、PostgreSQLのドキュメントを参照してください。

以下のGUCパラメータにより、PG-StromがBRINインデックスを使用するかどうかを制御する事ができます。デバッグやトラブルシューティングの場合を除き、通常は初期設定のままで構いません。

パラメータ名 初期値 説明
pg_strom.enable_brin bool on BRINインデックスを使用するかどうかを制御する。

操作

EXPLAIN構文によりBRINインデックスが使用されているかどうかを確認する事ができます。

postgres=# EXPLAIN ANALYZE
           SELECT * FROM dt
            WHERE ymd BETWEEN '2018-01-01' AND '2018-12-31'
              AND cat LIKE '%aaa%';
                                   QUERY PLAN
--------------------------------------------------------------------------------
 Custom Scan (GpuScan) on dt  (cost=94810.93..176275.00 rows=169992 width=44)
                              (actual time=1777.819..1901.537 rows=175277 loops=1)
   GPU Filter: ((ymd >= '2018-01-01'::date) AND (ymd <= '2018-12-31'::date) AND (cat ~~ '%aaa%'::text))
   Rows Removed by GPU Filter: 4385491
   BRIN cond: ((ymd >= '2018-01-01'::date) AND (ymd <= '2018-12-31'::date))
   BRIN skipped: 424704
 Planning time: 0.529 ms
 Execution time: 2323.063 ms
(7 rows)

上記の例ではymd列にBRINインデックスが設定されており、BRIN condの表示はBRINインデックスによる絞り込み条件を、BRIN skippedの表示はBRINインデックスにより実際に読み飛ばされたブロックの数を示しています。

この例では424704ブロックが読み飛ばされ、さらに、読み込んだブロックに含まれているレコードのうち4385491行が条件句によってフィルタされた事が分かります。

データ転送のロスを減らすため、GpuJoinやGpuPreAggが直下のテーブルスキャンを引き上げ、自らテーブルのスキャン処理を行う事があります。この場合でも、BRINインデックスが利用可能であればインデックスによる絞り込みを行います。 以下の例は、GROUP BYを含む処理でBRINインデックスが使用されているケースです。

postgres=# EXPLAIN ANALYZE
           SELECT cat,count(*)
             FROM dt WHERE ymd BETWEEN '2018-01-01' AND '2018-12-31'
         GROUP BY cat;
                                   QUERY PLAN
--------------------------------------------------------------------------------
 GroupAggregate  (cost=6149.78..6151.86 rows=26 width=12)
                 (actual time=427.482..427.499 rows=26 loops=1)
   Group Key: cat
   ->  Sort  (cost=6149.78..6150.24 rows=182 width=12)
             (actual time=427.465..427.467 rows=26 loops=1)
         Sort Key: cat
         Sort Method: quicksort  Memory: 26kB
         ->  Custom Scan (GpuPreAgg) on dt  (cost=6140.68..6142.95 rows=182 width=12)
                                            (actual time=427.331..427.339 rows=26 loops=1)
               Reduction: Local
               Outer Scan: dt  (cost=4000.00..4011.99 rows=4541187 width=4)
                               (actual time=78.573..415.961 rows=4560768 loops=1)
               Outer Scan Filter: ((ymd >= '2018-01-01'::date) AND (ymd <= '2018-12-31'::date))
               Rows Removed by Outer Scan Filter: 15564
               BRIN cond: ((ymd >= '2018-01-01'::date) AND (ymd <= '2018-12-31'::date))
               BRIN skipped: 424704
 Planning time: 30.992 ms
 Execution time: 818.994 ms
(14 rows)