PostgreSQLの新機能BRIN INDEXを使ってみた。

2016.03.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

BRIN INDEXを使うとビッグデータの検索が高速になるとの事なので気になって調べてみました。

試してみる

テーブル定義

CREATE TABLE table_brin (
id serial,
title VARCHAR(20),
date_normal DATE,
date_index DATE,
PRIMARY KEY(id),
CONSTRAINT date_brinindex_key UNIQUE(date_index));
# \d table_brin
                                   Table "public.table_brin"
   Column    |         Type          |                        Modifiers                        
-------------+-----------------------+---------------------------------------------------------
 id          | integer               | not null default nextval('table_brin_id_seq'::regclass)
 title       | character varying(20) | 
 date_normal | date                  | 
 date_index  | date                  | 
Indexes:
    "table_brin_pkey" PRIMARY KEY, btree (id)

ここに1000万件のデータを持つCSVをcopyで入れます。
CSVの容量は471.9MBでした。

こんなテーブルになります。
日付を表すdate_normalとdate_indexの値が1日づつ増えるテーブルです。

    id    |     title      | date_normal | date_index  
----------+----------------+-------------+-------------
        1 |  title1        | 2016-03-02  | 2016-03-02
        2 |  title2        | 2016-03-03  | 2016-03-03
        3 |  title3        | 2016-03-04  | 2016-03-04
        4 |  title4        | 2016-03-05  | 2016-03-05
        5 |  title5        | 2016-03-06  | 2016-03-06
.
.
.
  9999998 |  title9999998  | 29395-03-25 | 29395-03-25
  9999999 |  title9999999  | 29395-03-26 | 29395-03-26
 10000000 |  title10000000 | 29395-03-27 | 29395-03-27

次はBRIN INDEXを適用してから計測してみます。

BRIN INDEX構文

CREATE INDEX インデックス名 ON テーブル名 USING brin(カラム名);

BRIN INDEX実行

date_indexをBRIN INDEXに適用させます。

CREATE INDEX index_brin ON table_brin USING brin(date_index);

3528.346msかかりました。
テーブル定義を確認してみます。

# \d table_brin
                                   Table "public.table_brin"
   Column    |         Type          |                        Modifiers                        
-------------+-----------------------+---------------------------------------------------------
 id          | integer               | not null default nextval('table_brin_id_seq'::regclass)
 title       | character varying(20) | 
 date_normal | date                  | 
 date_index  | date                  | 
Indexes:
    "table_brin_pkey" PRIMARY KEY, btree (id)
    "index_brin" brin (date_index)

Indexesにindex_brinが追加されていますね。

SELECT実行例1

最初に\timingで処理時間を表示させる設定にします。
それからBRIN INDEXの対象では無いdate_normalで検索してみます。

# \timing
Timing is on.
SELECT COUNT(*) FROM table_brin WHERE date_normal BETWEEN '2016-04-01' AND '2100-01-01';
  count 
-------
 25789
(1 row)

Time: 2097.534 ms

2097.534msでした。

次は、BRIN INDEXの対象で有るdate_indexで検索してみます。

SELECT COUNT(*) FROM table_brin WHERE date_index BETWEEN '2016-04-01' AND '2100-01-01';
 count 
-------
 25789
(1 row)

Time: 23.848 ms

23.848msとなり、数値上も体感上も違いが出ました。

SELECT実行例2

今度は検索範囲を広げてみます。
まずはdate_normalで検索。

# SELECT COUNT(*) FROM table_brin WHERE date_normal BETWEEN '2016-04-01' AND '25000-01-01';
  count  
---------
 7078989
(1 row)

Time: 2738.185 ms

実行例1より少し増えました。

次にdate_indexで検索。

# SELECT COUNT(*) FROM table_brin WHERE date_index BETWEEN '2016-04-01' AND '25000-01-01';
  count  
---------
 7078989
(1 row)

Time: 2997.346 ms

date_normalを越えてしまいました。
1000万件でこれなので1億件だったら...

さいごに

使い分けが必要だと感じました。
他の条件で試してみたらまた違う結果になるかもしれないので、みなさんも是非試してみてください。