postgresqlで(3列の)複合主キーを持つテーブルを作成しました。先頭の列を含まないクエリでサブセットを使用すると、デフォルトのインデックスが使用されない。インデックスを明示的に作成する場合はそうではありません (インデックスはサブセットに使用されます)。
デフォルトでは、postgres は主キーにインデックスを作成します。しかし、postgreドキュメントが言うように
A multicolumn B-tree index can be used with query conditions that involve any subset of
the index's columns, but the index is most efficient when there are constraints on the leading (leftmost) columns.
クエリに先頭の列が含まれていない場合は、インデックスも使用されます (インデックスを明示的に作成した場合)。
以下は、サブセットで機能しないスキーマとクエリです。
# \d client_data
Table "public.client_data"
Column | Type | Modifiers
--------------------+-----------------------+-----------
macaddr | character varying(64) | not null
ts | bigint | not null
interval | smallint | not null
snr | smallint | not null
rx_rate | bigint |
tx_rate | bigint |
rx_data | bigint |
tx_data | bigint |
Indexes:
"client_data_pkey" PRIMARY KEY, btree (macaddr, ts, interval)
すべての主キー列を指定すると、クエリ プランナーはインデックス作成を使用します
# explain analyze select count(*) from client_data where macaddr='a:b:c' and ts=346783556 and interval=5;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=8.60..8.61 rows=1 width=0) (actual time=0.040..0.041 rows=1 loops=1)
-> Index Scan using client_data_pkey on client_data (cost=0.00..8.59 rows=1 width=0) (actual time=0.037..0.037 rows=0 loops=1)
Index Cond: (((macaddr)::text = 'a:b:c'::text) AND (ts = 346783556) AND ("interval" = 5))
Total runtime: 0.096 ms
(4 rows)
ただし、サブセットを指定すると、クエリ プランナーはインデックス作成を使用しません。
# explain analyze select count(*) from client_data where ts=346783556;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
Aggregate (cost=16176.01..16176.02 rows=1 width=0) (actual time=78.937..78.938 rows=1 loops=1)
-> Seq Scan on client_data (cost=0.00..16175.92 rows=36 width=0) (actual time=78.932..78.932 rows=0 loops=1)
Filter: (ts = 346783556)
Total runtime: 78.975 ms
(4 rows)
# explain analyze select count(*) from client_data where ts=346783556 and interval=5;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Aggregate (cost=17639.11..17639.12 rows=1 width=0) (actual time=78.815..78.815 rows=1 loops=1)
-> Seq Scan on client_data (cost=0.00..17639.11 rows=1 width=0) (actual time=78.810..78.810 rows=0 loops=1)
Filter: ((ts = 346783556) AND ("interval" = 5))
Total runtime: 78.853 ms
(4 rows)
しかし、ts または interval のいずれかで先行列 (macaddr) を使用すると、索引付けが使用されます。
# explain analyze select count(*) from client_data where macaddr='a' and ts=346783556;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=8.59..8.60 rows=1 width=0) (actual time=0.055..0.056 rows=1 loops=1)
-> Index Scan using client_data_pkey on client_data (cost=0.00..8.59 rows=1 width=0) (actual time=0.051..0.051 rows=0 loops=1)
Index Cond: (((macaddr)::text = 'a'::text) AND (ts = 346783556))
Total runtime: 0.103 ms
(4 rows)
# explain analyze select count(*) from client_data where macaddr='a' and interval=56;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=56.15..56.16 rows=1 width=0) (actual time=0.021..0.022 rows=1 loops=1)
-> Index Scan using client_data_pkey on client_data (cost=0.00..56.15 rows=1 width=0) (actual time=0.017..0.017 rows=0 loops=1)
Index Cond: (((macaddr)::text = 'a'::text) AND ("interval" = 56))
Total runtime: 0.055 ms
(4 rows)