4

マニュアルで説明されているように、PostgreSQL 9.2 にパーティション分割した大きなテーブルがあります。よくほとんど!私の実際のパーティション キーは、パーティション分割されたテーブル自体にはありませんが、次のように (簡略化して) 結合されたテーブルにあります。

-- millions to tens of millions of rows
CREATE TABLE data
(
  slice_id integer NOT NULL,
  point_id integer NOT NULL,
  -- ... data columns ...,
  CONSTRAINT pk_data PRIMARY KEY (slice_id, point_id),
  CONSTRAINT fk_data_slice FOREIGN KEY (slice_id) REFERENCES slice (id)
  CONSTRAINT fk_data_point FOREIGN KEY (point_id) REFERENCES point (id)
)

-- hundreds to thousands of rows
CREATE TABLE slice
(
  id serial NOT NULL,
  partition_date timestamp without time zone NOT NULL,
  other_date timestamp without time zone NOT NULL,
  int_key integer NOT NULL
  CONSTRAINT pk_slice PRIMARY KEY (id)
)

-- about 40,000 rows
CREATE TABLE point
(
  -- ... similar to "slice" ...
)

分割するテーブル ( data) には、 と のすべての組み合わせの行が含まれてpointおりslice、それぞれに複合キーがあります。partition_dateの一部であるキー列の 1 つだけでパーティション分割したいと考えていますslice。もちろん、子テーブルのチェック制約にそれを直接含めることはできないため、代わりに、次のように、それにslice.id対応するすべての値の範囲を含めますpartition_date

ALTER TABLE data_part_123 ADD CONSTRAINT ck_data_part_123
    CHECK (slice_id >= 1234 AND slice_id <= 1278);

これはすべて、データを挿入するために正常に機能します。ただし、クエリは上記の CHECK 制約を使用しません。例えば。

SELECT *
FROM data d
JOIN slice s ON d.slice_id = s.id
WHERE s.partition_date = '2013-07-23'

クエリ プランを見ると、これでもすべての子テーブルがスキャンされていることがわかります。CTE やサブセレクトなど、いくつかの方法でクエリを書き直そうとしましたが、役に立ちませんでした。

プランナーに私のパーティショニング スキームを「理解」させる方法はありますか? dataテーブル内でパーティション キーを何百万回も複製したくありません。

クエリ プランは次のようになります。

Aggregate  (cost=539243.88..539243.89 rows=1 width=0)
  ->  Hash Join  (cost=8.88..510714.02 rows=11411945 width=0)
        Hash Cond: (d.slice_id = s.id)
        ->  Append  (cost=0.00..322667.41 rows=19711542 width=4)
              ->  Seq Scan on data d  (cost=0.00..0.00 rows=1 width=4)
              ->  Seq Scan on data_part_123 d  (cost=0.00..135860.10 rows=8299610 width=4)
              ->  Seq Scan on data_part_456 d  (cost=0.00..186807.31 rows=11411931 width=4)
        ->  Hash  (cost=7.09..7.09 rows=143 width=4)
              ->  Seq Scan on slice s  (cost=0.00..7.09 rows=143 width=4)
                    Filter: (partition_date = '2013-07-23 00:00:00'::timestamp without time zone)
4

2 に答える 2