

# 테이블 파티션 지원
<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\$13단계를 반복합니다.

이런 파라미터에 대한 자세한 내용은 [Aurora PostgreSQL 쿼리 계획 관리를 위한 파라미터 참조](AuroraPostgreSQL.Optimize.Parameters.md) 섹션을 참조하세요.

## 테이블 파티션에 대한 계획 캡처
<a name="AuroraPostgreSQL.QPM.Partitiontable.capture"></a>

QPM에서는 다양한 계획이 `plan_hash` 값으로 구분됩니다. `plan_hash`가 어떻게 변하는지 이해하려면 먼저 비슷한 종류의 계획을 이해해야 합니다.

계획이 동일한 것으로 간주되려면 Append 노드 수준에서 누적된 액세스 방법, 숫자 제거 인덱스 이름 및 숫자 제거 파티션 이름의 조합이 일정해야 합니다. 계획에서 액세스하는 특정 파티션은 중요하지 않습니다. 다음 예제에서는 파티션이 4개인 `tbl_a` 테이블이 생성됩니다.

```
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)
```

상위 수준에서 액세스 방법, 숫자 제거 인덱스 이름 및 숫자 제거 파티션 이름이 `SeqScan tbl_a`, `IndexScan (i_idx) tbl_a`이므로 다음 3가지 계획도 동일한 것으로 간주됩니다.

```
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)
```

이 경우 두 파티션에서 읽어 들이는 계획은 실행되지 않습니다. 승인된 계획의 모든 조합(액세스 방법, 인덱스 이름)을 사용할 수 없으면 계획을 적용할 수 없습니다. 예를 들어 다음 계획에는 서로 다른 계획 해시가 있으며 이러한 경우에는 승인된 계획을 적용할 수 없습니다.

```
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`인 파티셔닝 테이블에 인덱스 이름이 `tA_col1_idx1`인 인덱스가 있는 경우 이름이 `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)
```

두 계획이 동일하게 보일 수도 있지만 하위 테이블의 이름 때문에 `Plan Hash` 값이 다릅니다. 테이블 이름이 숫자만이 아닌 영문자에 따라 다양하므로 적용이 실패합니다.