次のような分割テーブル構造があります。
CREATE TABLE measurements (
sensor_id bigint,
tx timestamp,
measurement int
);
CREATE TABLE measurements_201201(
CHECK (tx >= '2012-01-01 00:00:00'::timestamp without time zone
AND tx < ('2012-01-01 00:00:00'::timestamp without time zone + '1 mon'::interval))
)INHERITS (measurements);
CREATE INDEX ON measurements_201201(sensor_id);
CREATE INDEX ON measurements_201201(tx);
CREATE INDEX ON measurements_201201(sensor_id, tx);
....
等々。各テーブルには約2,000万行があります。
WHERE
節のセンサーのサンプルとタイムスタンプのサンプルをクエリすると、クエリプランは正しいテーブルが選択され、インデックスが使用されていることを示します。例:
SELECT *
FROM measurements
INNER JOIN sensors TABLESAMPLE BERNOULLI (0.01) USING (sensor_id)
WHERE tx BETWEEN '2015-01-04 05:00' AND '2015-01-04 06:00'
OR tx BETWEEN '2015-02-04 05:00' AND '2015-02-04 06:00'
OR tx BETWEEN '2014-03-05 05:00' AND '2014-04-07 06:00' ;
ただし、CTEを使用する場合、またはタイムスタンプ値をテーブルに配置する場合(一時テーブルにインデックスがあっても表示されません)。
WITH sensor_sample AS(
SELECT sensor_id, start_ts, end_ts
FROM sensors TABLESAMPLE BERNOULLI (0.01)
CROSS JOIN (VALUES (TIMESTAMP '2015-01-04 05:00', TIMESTAMP '2015-01-04 06:00'),
(TIMESTAMP '2015-02-04 05:00', TIMESTAMP '2015-02-04 06:00'),
(TIMESTAMP '2014-03-05 05:00', '2014-04-07 06:00') ) tstamps(start_ts, end_ts)
)
以下のようなもの
SET constraint_exclusion = on;
SELECT * FROM measurements
INNER JOIN sensor_sample USING (sensor_id)
WHERE tx BETWEEN start_ts AND end_ts
すべてのテーブルでインデックススキャンを実行します。これはまだ比較的高速ですが、クエリの複雑さが増すと、これはseqスキャンになり、パーティションテーブルの限られたサブセット(50のうち4-5)から最大40K行を取得するのに非常に遅くなる可能性があります。
自明ではない式の場合、PostgresクエリプランナーがCHECK制約に依存できることをPostgresクエリプランナーに理解させるために、クエリ内で多かれ少なかれ逐語的な条件を繰り返す必要があります。冗長に見えても!
すべてのデータに対してシーケンススキャンを実行する可能性を減らすために、パーティション化とクエリ構造を改善するにはどうすればよいですか?