すべてのプロダクト
Search
ドキュメントセンター

PolarDB:パーティションの剪定

最終更新日:Aug 23, 2024

PolarDB for PostgreSQL (Compatible with Oracle) は、パーティションプルーニング機能をサポートしています。これにより、パーティションテーブルに対するクエリを大幅に高速化できます。

概要

パーティションプルーニングが有効になっている場合、クエリプランナーは各パーティションの定義を調べ、WHERE句を満たす行が含まれていないため、パーティションをスキャンする必要がないことを証明しようとします。 プランナがこれを証明できる場合、クエリプランナは、クエリプランからパーティションを除外または削除する。 パーティションプルーニングは、ディスクから取得するデータ量を大幅に削減し、処理時間を短縮するため、クエリのパフォーマンスとリソース使用率が向上します。

PolarDB for PostgreSQL (Oracle互換) では、実際のSQL文に基づいて静的または動的なプルーニングを使用できます。

  • 静的プルーニングは、事前にアクセスされたパーティションの情報を用いて、コンパイル中に実行される。 静的プルーニングの一般的なシナリオは、SQL文にパーティションキー列に定数リテラルを持つWHERE条件が含まれている場合です。

  • 動的プルーニングは実行時に実行されます。これは、ステートメントによってアクセスされる正確なパーティションが事前にわかっていないことを意味します。 動的プルーニングのシナリオ例は、WHERE条件が演算子または関数を使用する場合です。

説明
  • パーティションプルーニングは、プルーニングが実行されるオブジェクトの統計と、オブジェクトに対して実行されるステートメントの実行計画に影響します。

  • システムは、所望のレコードを含み得るパーティションのみにデータスキャンを制限する。 静的プルーニングと動的プルーニングはどちらも、実行プランからパーティションを除外することでクエリのパフォーマンスを向上させます。

  • パーティションプルーニングでは、サブパーティションテーブルのクエリや、複数の列に基づくRANGEメソッドを使用してパーティション分割されたテーブルのクエリを最適化できません。

制約除外と同様に、パーティションプルーニングは、WHERE句の修飾子が指定された形式を使用する場合にのみ、WHERE句を含むクエリを最適化します。 詳細については、「制約除外」をご参照ください。

Parameters

パラメーター

説明

polar_comp_enable_pruning

パーティションプルーニングを有効にするかどうかを指定します。 有効な値:

  • on (デフォルト): 特定のクエリをすばやくプルーニングするために、パーティションプルーニングが有効になります。

  • off: パーティションの剪定は無効です。

使用上の注意

パーティションタイプ

リストパーティションテーブルのクエリ

  • リストパーティションテーブルの場合、パーティションプルーニングはWHERE句を含むクエリをすばやくプルーニングできます。 WHERE句の演算子は、(=) 、IS NULL、またはIS NOT NULLに等しくすることができます。

    例:

    ------ Specify a list-partitioned table.
    CREATE TABLE sales_hist(..., country text, ...) 
        PARTITION BY LIST(country) (
        PARTITION americas VALUES('US', 'CA', 'MX'), 
        PARTITION europe VALUES('BE', 'NL', 'FR'), 
        PARTITION asia VALUES('JP', 'PK', 'CN'), 
        PARTITION others VALUES(DEFAULT)
    ) 
    ------ Extract the information that contains the following WHERE clauses from the list-partitioned table.
    WHERE country = 'US' WHERE country IS NULL;          

    最初のWHERE句が使用されている場合、パーティションはWHERE country = 'US' を満たさないため、パーティションプルーニングはeurope、asia、その他のパーティションを除外します。

    2番目のWHERE句が使用されている場合、これらのパーティションはWHERE country is NULLを満たさないため、パーティションプルーニングはアメリカ、ヨーロッパ、およびアジアのパーティションを除外します。

範囲パーティション分割テーブルのクエリ

  • 範囲パーティションテーブルの場合、パーティションプルーニングはWHERE句を含むクエリをすばやくプルーニングできます。 WHERE句の演算子は、(=) 、より大きい (>) 、より大きいか等しい (>=) 、より小さいか等しい (<) 、より小さいか等しい (<=) 、IS NULL、IS NOT NULL、またはBETWEENandで構成される式です。 例:

    WHERE size > 100 AND size <= 200 WHERE size BETWEEN 100 AND 200
    説明

    パーティションプルーニングでは、ORまたはIN演算子を含む式はサポートされません。

    例:

    ------ Specify a range-partitioned table.
    CREATE TABLE boxes(id int, size int, color text) 
      PARTITION BY RANGE(size)
    (
        PARTITION small VALUES LESS THAN(100),
        PARTITION medium VALUES LESS THAN(200),
        PARTITION large VALUES LESS THAN(300)
    )
    ------ Extract the information that contains the following WHERE clauses from the range-partitioned table. 
    WHERE size > 100-- Scan the medium and large partitions.
    WHERE size >= 100-- Scan the medium and large partitions.
    WHERE size =100-- Scan the medium partition.
    WHERE size <= 100-- Scan the small and medium partitions.
    WHERE size < 100-- Scan the small partition.
    WHERE size > 100 AND size < 199-- Scan the medium partition.
    WHERE size BETWEEN 100 AND 199-- Scan the medium partition.
    WHERE color = 'red' AND size = 100  -- Scan the medium partition.
    WHERE color = 'red' AND (size > 100 AND size < 199) -- Scan the medium partition.

ステージ

PolarDB for PostgreSQL (Oracleと互換) では、条件式は不変、安定、および揮発性に分類されます。 3種類の条件式は、3種類の枝刈りに対応する。

  • 定数リテラルなど、条件式が不変の場合は、オプティマイザーステージでパーティションプルーニングが実行されます。

  • now() を含む式など、条件式が安定している場合、パーティションプルーニングは初期の実行段階で実行されます。

  • random() を含む式など、条件式が揮発性である場合、パーティションプルーニングは後の実行ステージで実行されます。

オプティマイザステージでのパーティションの剪定

次の例は、オプティマイザーステージでパーティションプルーニングを実行する方法を示しています。

この例では、logdateフィールドをパーティションキーとして使用して、measurement_y2023q1measurement_y2023q2measurement_y2023q3measurement_y2023q4の4つのパーティションを含むmeasurementという名前のテーブルが作成されます。 各パーティションは、4分の1の2023のデータに対応します。

CREATE TABLE measurement(
    city_id         int not null,
    logdate         date not null,
    peaktemp        int,
    unitsales       int
) PARTITION BY RANGE (logdate);
CREATE TABLE measurement_y2023q1 PARTITION OF measurement
    FOR VALUES FROM ('2023-01-01') TO ('2023-04-01');
CREATE TABLE measurement_y2023q2 PARTITION OF measurement
    FOR VALUES FROM ('2023-04-01') TO ('2023-07-01');
CREATE TABLE measurement_y2023q3 PARTITION OF measurement
    FOR VALUES FROM ('2023-07-01') TO ('2023-10-01');
CREATE TABLE measurement_y2023q4 PARTITION OF measurement
    FOR VALUES FROM ('2023-10-01') TO ('2024-04-01');

logdate >= DATE '2023-10-01' の条件に基づいて測定テーブルを照会します。 EXPLAINコマンドの結果に示すように、1番目、2番目、3番目の4分の1のパーティションはデフォルトでプルーニングされます。 3つのパーティションのデータがlogdate >= DATE '2023-10-01 'の条件を満たしていないため、システムは3つのパーティションのデータを照会しません。 この例では、パーティションプルーニングはオプティマイザステージで実行されます。 フィルタ条件はパーティションキーのlogdateに基づいて指定され、条件式で使用されるDATE '2023-10-01 'は定数です。 条件式は、オプティマイザの初期化時に計算できます。

EXPLAIN SELECT * FROM measurement WHERE logdate >= DATE '2023-10-01';
                                 QUERY PLAN                                  
-----------------------------------------------------------------------------
 Append  (cost=0.00..34.09 rows=567 width=20)
   ->  Seq Scan on measurement_y2023q4  (cost=0.00..31.25 rows=567 width=20)
         Filter: (logdate >= '01-OCT-23 00:00:00'::date)
(3 rows)

初期のエグゼキューター段階でのパーティションの剪定

次の例では、最初の例で作成された測定テーブルを使用して、早期実行段階でパーティションプルーニングが実行される方法を説明します。

次の例では、最初の例と同じテーブル測定を使用し、同じクエリを実行します。 ただし、次の例で使用する条件式は、定数式から安定式now() に変わります。 新しい条件式はオプティマイザーステージでは計算できませんが、初期の実行ステージでは計算できます。 月が7月2023日の場合、第1四半期と第2四半期の2つのパーティションが削除されます (サブプラン削除済み: 2) 。 第3および第4四半期のパーティションのみをスキャンする必要がある。 この例では、パーティションプルーニングは、早期実行段階で実行されます。 フィルター条件はパーティションキーlogdateに基づいて指定され、条件式now() は安定しています。 条件式は、この段階で計算することができる。

EXPLAIN SELECT * FROM measurement WHERE logdate >= now();
                                 QUERY PLAN                                  
-----------------------------------------------------------------------------
 Append  (cost=0.00..153.34 rows=2268 width=20)
   Subplans Removed: 2
   ->  Seq Scan on measurement_y2023q3  (cost=0.00..35.50 rows=567 width=20)
         Filter: (logdate >= now())
   ->  Seq Scan on measurement_y2023q4  (cost=0.00..35.50 rows=567 width=20)
         Filter: (logdate >= now())
(6 rows)

後のエグゼキューター段階でのパーティションの剪定

次の例では、最初の例で作成された測定テーブルを使用して、後の実行段階でパーティションプルーニングが実行される方法を説明します。

次の例では、最初の例と同じテーブルを使用し、同じクエリを実行します。 ただし、次の例で使用する条件式は、定数式からvolatile subjoin (select to_date('2023-10-1 ')) に変わります。 新しい条件式は、実行の早い段階では計算できませんが、実行の遅い段階でのみ計算できます。

EXPLAIN ANALYZEコマンドの結果に示すように、最初の4分の3のパーティションにはタグが付けられます (実行されません) 。 この例では、パーティションプルーニングは、後の実行段階で実行されます。 このタイプのパーティションプルーニングは、volatile式、サブクエリ、サブ結合、および結合条件の式に適用できます。 フィルタ条件はパーティションキーのlogdateに基づいて指定され、条件式 (select to_date('2023-10-1 ')) はvolatile subjoinです。 条件式は、この段階で計算することができる。

EXPLAIN ANALYZE SELECT * FROM measurement WHERE logdate >= (select  to_date('2023-10-1'));
                                                      QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.01..136.35 rows=2268 width=20) (actual time=0.067..0.068 rows=0 loops=1)
   InitPlan 1 (returns $0)
     ->  Result  (cost=0.00..0.01 rows=1 width=8) (actual time=0.051..0.053 rows=1 loops=1)
   ->  Seq Scan on measurement_y2023q1  (cost=0.00..31.25 rows=567 width=20) (never executed)
         Filter: (logdate >= $0)
   ->  Seq Scan on measurement_y2023q2  (cost=0.00..31.25 rows=567 width=20) (never executed)
         Filter: (logdate >= $0)
   ->  Seq Scan on measurement_y2023q3  (cost=0.00..31.25 rows=567 width=20) (never executed)
         Filter: (logdate >= $0)
   ->  Seq Scan on measurement_y2023q4  (cost=0.00..31.25 rows=567 width=20) (actual time=0.004..0.004 rows=0 loops=1)
         Filter: (logdate >= $0)

選択

CREATE TABLE sales
(
  dept_no     number,   
  part_no     varchar2,
  country     varchar2(20),
  date        date,
  amount      number
)
PARTITION BY LIST(country)
(
  PARTITION europe VALUES('FRANCE', 'ITALY'),
  PARTITION asia VALUES('INDIA', 'PAKISTAN'),
  PARTITION americas VALUES('US', 'CANADA')
);

------Perform a constrained query that contains the EXPLAIN statement. In this case, the server scans only the sales_asia table and stores records whose country value in the table is INDIA.
EXPLAIN (COSTS OFF) SELECT * FROM sales WHERE country = 'INDIA';
                    QUERY PLAN                     
---------------------------------------------------
 Append
   ->  Seq Scan on sales
         Filter: ((country)::text = 'INDIA'::text)
   ->  Seq Scan on sales_asia
         Filter: ((country)::text = 'INDIA'::text)
(5 rows)

------Perform the following query to search records that are included in the partition key. In this case, the server scans only the sales_asia table and stores records whose country value in the table is INDIA.
EXPLAIN (COSTS OFF) SELECT * FROM sales WHERE dept_no = '30'; 
               QUERY PLAN               
-----------------------------------------
 Append
   ->  Seq Scan on sales
         Filter: (dept_no = 30::numeric)
   ->  Seq Scan on sales_europe
         Filter: (dept_no = 30::numeric)
   ->  Seq Scan on sales_asia
         Filter: (dept_no = 30::numeric)
   ->  Seq Scan on sales_americas
         Filter: (dept_no = 30::numeric)
(9 rows)

制約除外は、サブパーティションテーブルのクエリにも使用できます。 次のステートメントでは、サブパーティションテーブルを作成する方法の例を示します。

CREATE TABLE sales
(
  dept_no     number,
  part_no     varchar2,
  country     varchar2(20),
  date        date,
  amount      number
)
PARTITION BY RANGE(date) SUBPARTITION BY LIST (country)
(
  PARTITION "2011" VALUES LESS THAN('01-JAN-2012')
  (
    SUBPARTITION europe_2011 VALUES ('ITALY', 'FRANCE'),
    SUBPARTITION asia_2011 VALUES ('PAKISTAN', 'INDIA'),
    SUBPARTITION americas_2011 VALUES ('US', 'CANADA')
  ),
  PARTITION "2012" VALUES LESS THAN('01-JAN-2013')
  (
    SUBPARTITION europe_2012 VALUES ('ITALY', 'FRANCE'),
    SUBPARTITION asia_2012 VALUES ('PAKISTAN', 'INDIA'),
    SUBPARTITION americas_2012 VALUES ('US', 'CANADA')
  ),
  PARTITION "2013" VALUES LESS THAN('01-JAN-2014')
  (
    SUBPARTITION europe_2013 VALUES ('ITALY', 'FRANCE'),
    SUBPARTITION asia_2013 VALUES ('PAKISTAN', 'INDIA'),
    SUBPARTITION americas_2013 VALUES ('US', 'CANADA')
  )
);

------ When you query the sales table, the query planner prunes all partitions or subpartitions that may not include desired result sets from the search path.
EXPLAIN (COSTS OFF) SELECT * FROM sales WHERE country = 'US' AND date = 'Dec 12, 2012';
                                 QUERY PLAN                                 
-----------------------------------------------------------------------------
 Append
   ->  Seq Scan on sales
         Filter: (((country)::text = 'US'::text) AND (date = '12-DEC-12 00:00:00'::timestamp without time zone))
   ->  Seq Scan on sales_2012
         Filter: (((country)::text = 'US'::text) AND (date = '12-DEC-12 00:00:00'::timestamp without time zone))
   ->  Seq Scan on sales_americas_2012
         Filter: (((country)::text = 'US'::text) AND (date = '12-DEC-12 00:00:00'::timestamp without time zone))
(7 rows)

更新と削除

CREATE TABLE t1_hash (id int , value int) PARTITION BY hash(id) partitions 4;

------ UPDATE operation
EXPLAIN UPDATE t1_hash SET value = value+1 WHERE id = least(1,2);
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Update on t1_hash  (cost=0.00..92.18 rows=24 width=14)
   Update on t1_hash_p1
   Update on t1_hash_p2 t1_hash
   ->  Append  (cost=0.00..92.18 rows=24 width=14)
         Subplans Removed: 1
         ->  Seq Scan on t1_hash_p1  (cost=0.00..46.03 rows=12 width=14)
               Filter: (id = LEAST(1, 2))
(7 rows)

------ DELETE operation
EXPLAIN DELETE FROM t1_hash WHERE id = least(1,2);
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Delete on t1_hash  (cost=0.00..92.12 rows=24 width=10)
   Delete on t1_hash_p1
   Delete on t1_hash_p2 t1_hash
   ->  Append  (cost=0.00..92.12 rows=24 width=10)
         Subplans Removed: 1
         ->  Seq Scan on t1_hash_p1  (cost=0.00..46.00 rows=12 width=10)
               Filter: (id = LEAST(1, 2))
(7 rows)

追加情報

制約除外

Parameters

パラメーター

説明

constraint_exclusion

制約除外を有効にするかどうかを指定します。 有効な値:

  • partition (デフォルト): 制約除外が有効になっています。

  • on: 制約除外が有効になっています。

  • off: 制約除外は無効です。

制約除外を有効にすると、サーバーは各パーティションに定義された制約をチェックして、パーティションがクエリを満たしているかどうかを判断します。

  • WHERE句を含まないSELECTステートメントを実行する場合、クエリプランナーはテーブル全体を検索する実行プランを推奨します。

  • WHERE句を含むSELECTステートメントを実行すると、クエリプランナーはレコードを格納するパーティションを決定し、指定したパーティションにクエリフラグメントを送信します。 次に、クエリプランナは、実行プランからのレコードを含むことができないパーティションをプルーニングする。

パーティションテーブルを使用しない場合は、パフォーマンスを向上させるために制約除外を無効にすることを推奨します。

パーティションプルーニングと制約除外の違い

パーティションプルーニングと制約除外は、次の点で異なります。

  • システムがパーティションプルーニングを実行するとき、パーティション間の関係を考慮に入れる。 これは、制約除外の場合には当てはまらない。

    例えば、パーティション・プルーニングに従って、リスト・パーティション・テーブル内の特定のレコードを検索するとき、システムは、レコードが格納されているパーティションを知る。 しかしながら、制約除外中に、システムは、各パーティションに対して定義された制約をチェックしなければならない。

  • パーティションプルーニングは、プランナが見る必要のあるパーティションの数を減らすために、最適化段階の初期段階で実行されます。 しかし、制約排除は、最適化の後段で実行される。