

# テーブルパーティションのサポート
<a name="AuroraPostgreSQL.QPM.Partitiontable"></a>

Aurora PostgreSQL クエリプラン管理 (QPM) は、以下のバージョンで宣言的テーブルパーティショニングをサポートしています。
+ 15.3 以降の 15 バージョン
+ 14.8 以降の 14 バージョン
+ 13.11 以降の 13 バージョン

詳細については、「[テーブルのパーティション](https://www.postgresql.org/docs/current/ddl-partitioning.html)」を参照してください。

**Topics**
+ [テーブルパーティションの設定](#AuroraPostgreSQL.QPM.Partitiontable.setup)
+ [テーブルパーティションのプランのキャプチャ](#AuroraPostgreSQL.QPM.Partitiontable.capture)
+ [テーブルパーティションプランの実施](#AuroraPostgreSQL.QPM.Partitiontable.enforcement)
+ [命名規則](#AuroraPostgreSQL.QPM.Partitiontable.naming.convention)

## テーブルパーティションの設定
<a name="AuroraPostgreSQL.QPM.Partitiontable.setup"></a>

 Aurora PostgreSQL QPM でテーブルパーティションをセットアップするには、以下の手順を実行してください。

1. DB クラスターパラメータグループで `apg_plan_mgmt.plan_hash_version` を 3 以上に設定します。

1. クエリプラン管理を使用し、`apg_plan_mgmt.dba_plans` ビューにエントリがあるデータベースに移動します。

1. `apg_plan_mgmt.validate_plans('update_plan_hash')` を呼び出して、プランテーブルの `plan_hash` 値を更新します。

1. クエリプラン管理が有効になっていて、`apg_plan_mgmt.dba_plans` ビューにエントリがあるすべてのデータベースについて、手順 2～3 を繰り返します。

これらのパラメータの詳細については、「[Aurora PostgreSQL クエリ計画管理のパラメータリファレンス](AuroraPostgreSQL.Optimize.Parameters.md)」を参照してください。

## テーブルパーティションのプランのキャプチャ
<a name="AuroraPostgreSQL.QPM.Partitiontable.capture"></a>

QPM では、さまざまなプランが `plan_hash` 値によって区別されます。`plan_hash` がどのように変化するかを理解するには、まず、同様の種類のプランを理解する必要があります。

Append ノードレベルで蓄積されるアクセス方法、数字を取り除いたインデックス名、および数字を取り除いたパーティション名の組み合わせが同じであれば、プランは同じと見なされます。プランでアクセスされる特定のパーティションは重要ではありません。次の例では、テーブル `tbl_a` は 4 つのパーティションで作成されます。

```
postgres=>create table tbl_a(i int, j int, k int, l int, m int) partition by range(i);
CREATE TABLE
postgres=>create table tbl_a1 partition of tbl_a for values from (0) to (1000);
CREATE TABLE
postgres=>create table tbl_a2 partition of tbl_a for values from (1001) to (2000);
CREATE TABLE
postgres=>create table tbl_a3 partition of tbl_a for values from (2001) to (3000);
CREATE TABLE
postgres=>create table tbl_a4 partition of tbl_a for values from (3001) to (4000);
CREATE TABLE
postgres=>create index t_i on tbl_a using btree (i);
CREATE INDEX
postgres=>create index t_j on tbl_a using btree (j);
CREATE INDEX
postgres=>create index t_k on tbl_a using btree (k);
CREATE INDEX
```

クエリが検索するパーティションの数に関係なく、単一のスキャン方法を使用して `tbl_a` をスキャンするため、次のプランは同じと見なされます。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 999 and j < 9910 and k > 50;
            
                        QUERY PLAN
-------------------------------------------------------------------
Seq Scan on tbl_a1 tbl_a
    Filter: ((i >= 990) AND (i <= 999) AND (j < 9910) AND (k > 50))
SQL Hash: 1553185667, Plan Hash: -694232056
(3 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
            
                        QUERY PLAN
-------------------------------------------------------------------
Append
    ->  Seq Scan on tbl_a1 tbl_a_1
            Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
    ->  Seq Scan on tbl_a2 tbl_a_2
            Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
    SQL Hash: 1553185667, Plan Hash: -694232056
    (6 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Seq Scan on tbl_a1 tbl_a_1
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a3 tbl_a_3
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -694232056
(8 rows)
```

次の 3 つのプランも同じとみなされます。親レベルで、アクセス方法、数字を取り除いたインデックス名、および数字を取り除いたパーティション名は、`SeqScan tbl_a`、`IndexScan (i_idx) tbl_a` であるためです。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Seq Scan on tbl_a1 tbl_a_1
         Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a2_i_idx on tbl_a2 tbl_a_2
         Index Cond: ((i >= 990) AND (i <= 1100))
         Filter: ((j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -993736942
(7 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -993736942
(10 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Seq Scan on tbl_a1 tbl_a_1
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a3 tbl_a_3
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a4_i_idx on tbl_a4 tbl_a_4
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -993736942
(11 rows)
```

子パーティション内の出現順序や出現回数が異なっていても、アクセス方法、数字を取り除いたインデックス名、および数字を取り除いたパーティション名は、上記の各プランの親レベルで同じです。

ただし、次の条件のいずれかが満たされる場合、プランは異なると見なされます。
+ プランで追加のアクセス方法が使用される。

  ```
  postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
                      
                                  QUERY PLAN
  --------------------------------------------------------------------------
   Append
     ->  Seq Scan on tbl_a1 tbl_a_1
           Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
     ->  Seq Scan on tbl_a2 tbl_a_2
           Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
     ->  Bitmap Heap Scan on tbl_a3 tbl_a_3
           Recheck Cond: ((i >= 990) AND (i <= 2100))
           Filter: ((j < 9910) AND (k > 50))
           ->  Bitmap Index Scan on tbl_a3_i_idx
                 Index Cond: ((i >= 990) AND (i <= 2100))
   SQL Hash: 1553185667, Plan Hash: 1134525070
  (11 rows)
  ```
+ プラン内のどのアクセス方法もそれ以上使用されない。

  ```
  postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
                      
                                 QUERY PLAN
  --------------------------------------------------------------------------
   Append
     ->  Seq Scan on tbl_a1 tbl_a_1
           Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
     ->  Seq Scan on tbl_a2 tbl_a_2
           Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
   SQL Hash: 1553185667, Plan Hash: -694232056
  (6 rows)
  ```
+ インデックスメソッドに関連付けられたインデックスが変更された。

  ```
  postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
                      
                               QUERY PLAN
  --------------------------------------------------------------------------
   Append
     ->  Seq Scan on tbl_a1 tbl_a_1
           Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
     ->  Index Scan using tbl_a2_j_idx on tbl_a2 tbl_a_2
           Index Cond: (j < 9910)
           Filter: ((i >= 990) AND (i <= 1100) AND (k > 50))
   SQL Hash: 1553185667, Plan Hash: -993343726
  (7 rows)
  ```

## テーブルパーティションプランの実施
<a name="AuroraPostgreSQL.QPM.Partitiontable.enforcement"></a>

パーティションテーブルについて承認されたプランは、位置対応で実施されます。プランはパーティションに固有ではなく、元のクエリで参照されているプラン以外のパーティションにも適用できます。プランには、最初に承認されたアウトラインとは異なる数のパーティションにアクセスするクエリを強制する機能もあります。

例えば、承認されたアウトラインが次のプランに関するものであるとします。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))   
 SQL Hash: 1553185667, Plan Hash: -993736942
(10 rows)
```

この場合、このプランは、2、4、またはそれ以上のパーティションを参照する SQL クエリにも適用できます。これらのシナリオで、2 パーティションと 4 パーティションのアクセスについて考えられるプランは以下のとおりです。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
            
                                QUERY PLAN
----------------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 1100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
 Note: An Approved plan was used instead of the minimum cost plan. 
 SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041
(8 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a4 tbl_a_4
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
 Note: An Approved plan was used instead of the minimum cost plan.
 SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041 
(12 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50;
            
                                QUERY PLAN
----------------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a4_i_idx on tbl_a4 tbl_a_4
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
 Note: An Approved plan was used instead of the minimum cost plan.
 SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041
(14 rows)
```

パーティションごとにアクセス方法が異なる別の承認済みプランを考えてみましょう。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Bitmap Heap Scan on tbl_a3 tbl_a_3
         Recheck Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
         ->  Bitmap Index Scan on tbl_a3_i_idx
               Index Cond: ((i >= 990) AND (i <= 2100))
 SQL Hash: 1553185667, Plan Hash: 2032136998
(12 rows)
```

この場合、2 つのパーティションからデータを読み込むプランは適用されません。承認されたプランの（アクセス方法、インデックス名）の組み合わせがすべて使用可能でない限り、プランを実施することはできません。例えば、以下のプランはプランのハッシュが異なり、承認されたプランはこのような場合には適用できません。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1900 and j < 9910 and k > 50;
            
                              QUERY PLAN
-------------------------------------------------------------------------
 Append
   ->  Bitmap Heap Scan on tbl_a1 tbl_a_1
         Recheck Cond: ((i >= 990) AND (i <= 1900))
         Filter: ((j < 9910) AND (k > 50))
         ->  Bitmap Index Scan on tbl_a1_i_idx
               Index Cond: ((i >= 990) AND (i <= 1900))
   ->  Bitmap Heap Scan on tbl_a2 tbl_a_2
         Recheck Cond: ((i >= 990) AND (i <= 1900))
         Filter: ((j < 9910) AND (k > 50))
         ->  Bitmap Index Scan on tbl_a2_i_idx
               Index Cond: ((i >= 990) AND (i <= 1900))
  Note: This is not an Approved plan.  No usable Approved plan was found.
  SQL Hash: 1553185667, Plan Hash: -568647260
(13 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1900 and j < 9910 and k > 50;
            
                              QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 1900))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 1900) AND (j < 9910) AND (k > 50))
 Note: This is not an Approved plan.  No usable Approved plan was found.
 SQL Hash: 1553185667, Plan Hash: -496793743
(8 rows)
```

## 命名規則
<a name="AuroraPostgreSQL.QPM.Partitiontable.naming.convention"></a>

QPM が宣言的パーティションテーブルでプランを適用するには、親テーブル、テーブルパーティション、インデックスに固有の命名規則に従う必要があります。
+ **親テーブル名** - これらの名前は、数字だけでなく、アルファベットまたは特殊文字が異なっていなければなりません。例えば、tA、tB、tC は個別の親テーブルには使用できる名前ですが、t1、t2、t3 はそうではありません。
+ **各パーティションテーブル名** - 同じ親を持つパーティション名は、数字のみが異なっている必要があります。例えば、tA に指定できるパーティション名は tA1、tA2、t1a、t2A、または複数桁の場合もあります。

  その他の違い (文字、特殊文字) があっても、プランの適用は保証されません。
+ **インデックス名** – パーティションテーブル階層で、すべてのインデックスに一意の名前があることを確認します。つまり、名前の数値以外の部分は異なっている必要があります。例えば、`tA_col1_idx1` という名前のインデックスを持つ `tA` という名前のパーティションテーブルがある場合、`tA_col1_idx2` という名前の別のインデックスを使用することはできません。ただし、`tA_a_col1_idx2` というインデックスは、数値以外の部分が一意であるため使用できます。このルールは、親テーブルと個々のパーティションテーブルの両方で作成されたインデックスに適用されます。

 上記の命名規則に従わないと、承認されたプランの実施に失敗する可能性があります。次の例は、このような実施が失敗したことを示しています。

```
postgres=>create table t1(i int, j int, k int, l int, m int) partition by range(i);
CREATE TABLE
postgres=>create table t1a partition of t1 for values from (0) to (1000);
CREATE TABLE
postgres=>create table t1b partition of t1 for values from (1001) to (2000);
CREATE TABLE
postgres=>SET apg_plan_mgmt.capture_plan_baselines TO 'manual';
SET
postgres=>explain (hashes true, costs false) select count(*) from t1 where i > 0;

                            QUERY PLAN
--------------------------------------------------------------------------
 Aggregate
   ->  Append
         ->  Seq Scan on t1a t1_1
               Filter: (i > 0)
         ->  Seq Scan on t1b t1_2
               Filter: (i > 0)
 SQL Hash: -1720232281, Plan Hash: -1010664377
(7 rows)
```

```
postgres=>SET apg_plan_mgmt.use_plan_baselines TO 'on';
SET
postgres=>explain (hashes true, costs false) select count(*) from t1 where i > 1000;

                            QUERY PLAN
-------------------------------------------------------------------------
 Aggregate
   ->  Seq Scan on t1b t1
         Filter: (i > 1000)
 Note: This is not an Approved plan. No usable Approved plan was found.
 SQL Hash: -1720232281, Plan Hash: 335531806
(5 rows)
```

2 つのプランは同じように見えますが、子テーブルの名前によって `Plan Hash` 値は異なります。数値のみでなくアルファベット文字で名前が異なるテーブルでは、プランの実施が失敗します。