マスターテーブルと2つの子テーブルを持つPostgreSQL 9.0.12データベースがあります。私のテーブル:
_CREATE TABLE test2 (
id serial PRIMARY KEY,
coll character varying(15),
ts timestamp without time zone
);
CREATE INDEX ON test2(ts);
CREATE TABLE test2_20150812 (
CHECK ( ts >= timestamp '2015-08-12' AND ts < timestamp '2015-08-13' )
) INHERITS (test2);
CREATE TABLE test2_20150811 (
CHECK ( ts >= timestamp '2015-08-11' AND ts < timestamp '2015-08-12' )
) INHERITS (test2);
CREATE INDEX ON test2_20150812(ts);
CREATE INDEX ON test2_20150811(ts);
VACUUM FULL ANALYZE;
_
私の選択クエリの説明結果(dbには行がありません):
_EXPLAIN (ANALYZE, BUFFERS) select * from test2 WHERE ts >= '2015-08-11' ORDER BY ts DESC;
Sort (cost=89.87..92.09 rows=887 width=31) (actual time=0.245..0.245 rows=0 loops=1)
Sort Key: public.test2.ts
Sort Method: quicksort Memory: 17kB
Buffers: shared read=2
-> Result (cost=0.00..46.44 rows=887 width=31) (actual time=0.087..0.087 rows=0 loops=1)
Buffers: shared read=2
-> Append (cost=0.00..46.44 rows=887 width=31) (actual time=0.078..0.078 rows=0 loops=1)
Buffers: shared read=2
-> Seq Scan on test2 (cost=0.00..0.00 rows=1 width=31) (actual time=0.007..0.007 rows=0 loops=1)
Filter: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
-> Bitmap Heap Scan on test2_20150812 test2 (cost=7.68..23.22 rows=443 width=31) (actual time=0.024..0.024 rows=
0 loops=1)
Recheck Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
Buffers: shared read=1
-> Bitmap Index Scan on test2_20150812_ts_idx (cost=0.00..7.57 rows=443 width=0) (actual time=0.016..0.016
rows=0 loops=1)
Index Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
Buffers: shared read=1
-> Bitmap Heap Scan on test2_20150811 test2 (cost=7.68..23.22 rows=443 width=31) (actual time=0.033..0.033 rows=
0 loops=1)
Recheck Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
Buffers: shared read=1
-> Bitmap Index Scan on test2_20150811_ts_idx (cost=0.00..7.57 rows=443 width=0) (actual time=0.026..0.026
rows=0 loops=1)
Index Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
Buffers: shared read=1
Total runtime: 0.320 ms
(23 rows)
_
ただし、列coll
をcharacter varying(15)
からcharacter varying(255)
に変更し、これらの手順を再度実行すると、
_CREATE TABLE test2 (
id serial PRIMARY KEY,
coll character varying(255),
ts timestamp without time zone
);
_
説明の出力は次のとおりです(dbには行がありません):
_EXPLAIN (ANALYZE, BUFFERS) select * from test2 WHERE ts >= '2015-08-11' ORDER BY ts DESC;
Sort (cost=42.47..43.18 rows=287 width=157) (actual time=0.028..0.028 rows=0 loops=1)
Sort Key: public.test2.ts
Sort Method: quicksort Memory: 17kB
-> Result (cost=0.00..30.75 rows=287 width=157) (actual time=0.020..0.020 rows=0 loops=1)
-> Append (cost=0.00..30.75 rows=287 width=157) (actual time=0.015..0.015 rows=0 loops=1)
-> Seq Scan on test2 (cost=0.00..0.00 rows=1 width=157) (actual time=0.003..0.003 rows=0 loops=1)
Filter: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
-> Seq Scan on test2_20150812 test2 (cost=0.00..15.38 rows=143 width=157) (actual time=0.002..0.002 rows=0 loops
=1)
Filter: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
-> Seq Scan on test2_20150811 test2 (cost=0.00..15.38 rows=143 width=157) (actual time=0.002..0.002 rows=0 loops
=1)
Filter: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)
Total runtime: 0.063 ms
(12 rows)
_
この新しい条件で子テーブルのインデックスを使用する方法はありますか?
これはすべて、継承とパーティショニングとは無関係です。一般的には、インデックス作成とクエリプランについてです。
2回目の試行では、行サイズがはるかに大きくなります:_width=157
_と_width=46
_。 Postgresは/もっと簡単により広い行のインデックスを使用します。予期しない順次スキャンの考えられる理由は次のとおりです。
プランナーの見積もりで示されているように、2番目のテストではテーブルの行が大幅に少なくなっています:_rows=143
_と_rows=357
_。ソートする数行のみのインデックスを検索するのは無駄です。
または、統計が古くなり、誤ったプランナーの見積もりにつながります(Postgresのみthinks行が少なくなります)。
インデックスのサイズは、テーブルを書き換える副作用として膨らんだ可能性があります。 REINDEX
または_VACUUM FULL
_はそれを修復します。
関連するすべてのテーブルでANALYZE
を実行し、再試行してください-すべてのテーブルで同じ数の行を使用してください。ビットマップインデックススキャンが再び表示されます。現象が続く場合は、EXPLAIN
だけでなく、EXPLAIN (ANALYZE, BUFFERS)
の出力を提供してください。
whole tableを読んでいる限り、インデックスの用途は限られています。一致するインデックスを使用して単一テーブルをクエリし、インデックスから簡単にソートされた行を読み取ることができるようにし、Postgresが/ソート手順を完全にスキップできるようにする場合インデックススキャンが表示されます。
複数のテーブルを組み合わせる必要がある場合、これは不可能です。これは SQLフィドル で、子ごとに1万行があり、有効な統計は、予想どおりビットマップインデックススキャンを示しています。クエリを数回繰り返した後(テーブル全体がキャッシュされるとすぐに)、Postgresはインデックスをスキップして、順次スキャンに切り替える可能性があります。
Postgresは明らかに、相互に除外するチェック制約を理解するのに十分スマートではありません。これにより、各テーブルから簡単にソートされた結果を追加できますas is。could手動で指示することで強制します。
_(SELECT * FROM test2_20150812 ORDER BY ts DESC)
UNION ALL
(SELECT * FROM test2_20150811 ORDER BY ts DESC);
_
ただし、PostgresはMerge Append(事前にソートされたセットを結合するための安価な方法)を使用するのに十分スマートでなければなりません。 PostgreSQLのローカルテストでは、9.4実際に各パーティションでインデックススキャンがMerge Appendと組み合わせて表示されます。その計画はより良いですが、whole tableを読んでいる限り、インデックスの用途は限られているため、シーケンシャルスキャンほど高速ではありません。
_'QUERY PLAN'
'Merge Append (cost=0.73..16866.41 rows=200001 width=45)'
' Sort Key: test.ts'
' -> Index Scan Backward using test_ts_idx on test (cost=0.13..8.14 rows=1 width=528)'
' Index Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)'
' -> Index Scan Backward using test_20150811_ts_idx on test_20150811 (cost=0.29..6594.01 rows=100000 width=45)'
' Index Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)'
' -> Index Scan Backward using test_20150812_ts_idx on test_20150812 (cost=0.29..6594.29 rows=100000 width=45)'
' Index Cond: (ts >= '2015-08-11 00:00:00'::timestamp without time zone)'
_
Postgres 9.3(sqlfiddleでのテスト)では同じプランを取得していません。 9.3ページの制限である必要があります。 (?)
ただし、の古いバージョン9.0を使用しているため、それらのどれも使用できません。
Merge Appendは9.1で導入されました
結果を数行に制限すると、より興味深い結果が得られます。 varchar(15)
またはvarchar(255)
は、クエリプランにほとんど影響を与えません。幅の広いタイプは、インデックスをさらに優先します。
SQL Fiddleでのインデックスのテストについて: