【OracleDatabase】パーティション化によるパフォーマンスの向上について 

# OracleDatabaseにおけるパーティションとは
大きなテーブルやインデックスをより扱いやすい小さな単位に分割する機能です。
これにより、パフォーマンスの向上やメンテナンス性の向上が期待できます。

# パーティションのメリット
パーティションには多くのメリットがありますが、本記事では特にクエリパフォーマンスの向上に焦点を当てて解説します。

## 1. パフォーマンスの向上
パーティション化により、検索範囲が限定され、関連しないデータのスキャンを回避することで、クエリパフォーマンスの向上が期待できます。

## 2. メンテナンス性の向上
特定のパーティションのみをメンテナンス対象とすることで、作業時のリスクを局所化できます。また、メンテナンス時間の短縮により、システムの可用性が向上します。

## 3. 不要リソースの削減
`DROP PARTITION` コマンドにより、パーティション内のデータを一括で削除することが可能です。これは `DELETE` コマンドよりも遥かに高速です。また、関連するセグメントが解放され、表領域の使用量が実際に削減されます。`DELETE` の場合、セグメントの解放は直ちに行われず、表領域の使用量は即座には減少しません。

# パーティションの種類
Oracle Databaseでは、以下のようなパーティション方式が利用できます。
|パーティション方式|内容|
|---|---|
|レンジパーティション|特定の範囲の値に基づいて分割されます。日付や数値の範囲などに使用されます。|
|リストパーティション|指定された値のリストに基づいて分割されます。地域コードや製品カテゴリなどに使用されます。|
|ハッシュパーティション|ハッシュ関数を使用してデータを均等に分割します。|
|コンポジットパーティション|2つのパーティション方式を組み合わせたものです。例えば、レンジとハッシュの組み合わせなど。|
|インターバルパーティション|指定された間隔で自動的に新規パーティションを作成します。レンジパーティションの一種です。|
|リファレンスパーティション|外部キーによって関連付けられた親テーブルのパーティション方式に従います。|

# パーティション索引の種類
パーティション化されたテーブルに対する索引には、以下の種類があります。
|種類|内容|
|---|---|
|ローカル同一キー索引|テーブルと索引が同じキーでパーティション化されており、索引キーも同じです。|
|ローカル非同一キー索引|テーブルと索引が同じキーでパーティション化されていますが、索引キーが異なります。|
|グローバル・パーティション索引|テーブルのパーティションキーとは異なるキーで索引がパーティション化されています。|
|グローバル・非パーティション索引|テーブルはパーティション化されていますが、索引はパーティション化されていません。|

# パーティション索引と効率性
それぞれのパーティション索引がどのような場合に効率的にアクセスできるかについて、検証結果に基づいて記載します。

## 0. 検証データの準備
```
-- テーブル作成（パーティションキーは sale_date ）
CREATE TABLE sales (
    sale_id NUMBER,
    product_id NUMBER,
    sale_date DATE,
    amount NUMBER
)
PARTITION BY RANGE (sale_date) (
    PARTITION sales_2019q1 VALUES LESS THAN (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
    PARTITION sales_2019q2 VALUES LESS THAN (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
    PARTITION sales_2019q3 VALUES LESS THAN (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
    PARTITION sales_2019q4 VALUES LESS THAN (TO_DATE('2020-01-01', 'YYYY-MM-DD')),
    PARTITION sales_2020q1 VALUES LESS THAN (TO_DATE('2020-04-01', 'YYYY-MM-DD')),
    PARTITION sales_2020q2 VALUES LESS THAN (TO_DATE('2020-07-01', 'YYYY-MM-DD')),
    PARTITION sales_2020q3 VALUES LESS THAN (TO_DATE('2020-10-01', 'YYYY-MM-DD')),
    PARTITION sales_2020q4 VALUES LESS THAN (TO_DATE('2021-01-01', 'YYYY-MM-DD')),
    PARTITION sales_2021q1 VALUES LESS THAN (TO_DATE('2021-04-01', 'YYYY-MM-DD')),
    PARTITION sales_2021q2 VALUES LESS THAN (TO_DATE('2021-07-01', 'YYYY-MM-DD')),
    PARTITION sales_2021q3 VALUES LESS THAN (TO_DATE('2021-10-01', 'YYYY-MM-DD')),
    PARTITION sales_2021q4 VALUES LESS THAN (TO_DATE('2022-01-01', 'YYYY-MM-DD')),
    PARTITION sales_2022q1 VALUES LESS THAN (TO_DATE('2022-04-01', 'YYYY-MM-DD')),
    PARTITION sales_2022q2 VALUES LESS THAN (TO_DATE('2022-07-01', 'YYYY-MM-DD')),
    PARTITION sales_2022q3 VALUES LESS THAN (TO_DATE('2022-10-01', 'YYYY-MM-DD')),
    PARTITION sales_2022q4 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD')),
    PARTITION sales_2023q1 VALUES LESS THAN (TO_DATE('2023-04-01', 'YYYY-MM-DD')),
    PARTITION sales_2023q2 VALUES LESS THAN (TO_DATE('2023-07-01', 'YYYY-MM-DD')),
    PARTITION sales_2023q3 VALUES LESS THAN (TO_DATE('2023-10-01', 'YYYY-MM-DD')),
    PARTITION sales_2023q4 VALUES LESS THAN (TO_DATE('2024-01-01', 'YYYY-MM-DD'))
);

-- データの投入
BEGIN
  FOR i IN 1..100000 LOOP
    INSERT INTO sales (sale_id, product_id, sale_date, amount)
    VALUES (
      i,
      TRUNC(DBMS_RANDOM.VALUE(100, 2000)), -- 100から1999までのランダムなproduct_id
      TRUNC(TO_DATE('2019-01-01', 'YYYY-MM-DD') + DBMS_RANDOM.VALUE(0, 1460)), -- 2019年1月1日から2023年12月31日までのランダムな日付
      TRUNC(DBMS_RANDOM.VALUE(100, 2000)) -- 100から1999までのランダムなamount
    );
  END LOOP;
  COMMIT;
END;
/

-- 統計情報の取得
EXEC DBMS_STATS.GATHER_TABLE_STATS('test_user', 'sales', cascade => TRUE);
```

## 1. 「ローカル同一キー索引」の検証
パーティションキーがクエリに含まれる場合、検索対象パーティションが限定され、パーティション内でのローカルインデックスが利用されるため、クエリのパフォーマンスが向上します。

### ・索引の作成
```
CREATE INDEX sales_sale_date_idx ON sales(sale_date) LOCAL;
EXEC DBMS_STATS.GATHER_INDEX_STATS('test_user', 'sales_sale_date_idx');
```

### ・パーティションキー（sale_date）が含まれるクエリの実行
検索されるパーティションが限定され、さらに検索範囲内で索引が利用されるため効率的にアクセス可能です。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3937308092

----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                     |     1 |    48 |     1   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE                    |                     |     1 |    48 |     1   (0)| 00:00:01 |    17 |    17 |
|   2 |   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES               |     1 |    48 |     1   (0)| 00:00:01 |    17 |    17 |
|*  3 |    INDEX RANGE SCAN                        | SALES_SALE_DATE_IDX |     1 |       |     1   (0)| 00:00:01 |    17 |    17 |
----------------------------------------------------------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
```

### ・パーティションキーと他のキーが含まれるクエリの実行
パーティションキーのみの場合と同様に、検索されるパーティションが限定され、さらに検索範囲内で索引が利用されるため効率的にアクセス可能です。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD') AND product_id = 101;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3937308092

----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                     |     1 |    48 |     1   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE                    |                     |     1 |    48 |     1   (0)| 00:00:01 |    17 |    17 |
|*  2 |   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES               |     1 |    48 |     1   (0)| 00:00:01 |    17 |    17 |
|*  3 |    INDEX RANGE SCAN                        | SALES_SALE_DATE_IDX |     1 |       |     1   (0)| 00:00:01 |    17 |    17 |
----------------------------------------------------------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("PRODUCT_ID"=101)
   3 - access("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
```

### ・キーが含まれないクエリの実行
パーティションや索引による絞り込みができず、テーブルのフルスキャンが必要となります。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_id = 1234;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1550251865

---------------------------------------------------------------------------------------------
| Id  | Operation           | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |       |     1 |    21 |   124   (1)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE ALL|       |     1 |    21 |   124   (1)| 00:00:01 |     1 |    20 |
|*  2 |   TABLE ACCESS FULL | SALES |     1 |    21 |   124   (1)| 00:00:01 |     1 |    20 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("SALE_ID"=1234)
```

## 2. 「ローカル非同一キー索引」の検証
パーティションキーがクエリに含まれない場合でも、非同一キーに基づくローカルインデックスがあれば、それに基づいた検索が可能ですが、全パーティションにわたる検索が必要になる場合があります。

### ・索引の作成
```
CREATE INDEX sales_product_id_idx ON sales(product_id) LOCAL;
EXEC DBMS_STATS.GATHER_INDEX_STATS('test_user', 'sales_product_id_idx');
```

### ・パーティションキー（sale_date）が含まれるクエリの実行
パーティションにより検索範囲は限定されますが、対象パーティション内ではフルスキャンが実行されます。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4096232376

------------------------------------------------------------------------------------------------
| Id  | Operation              | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |       |     1 |    48 |     2   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE|       |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
|*  2 |   TABLE ACCESS FULL    | SALES |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
```

### ・非同一キー（product_id）が含まれるクエリの実行
索引により絞り込みは実施されますが、すべてのパーティションが検索されます。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE product_id = 101;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2414407334

-----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                 | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                      |    53 |  1113 |    70   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE ALL                       |                      |    53 |  1113 |    70   (0)| 00:00:01 |     1 |    20 |
|   2 |   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES                |    53 |  1113 |    70   (0)| 00:00:01 |     1 |    20 |
|*  3 |    INDEX RANGE SCAN                        | SALES_PRODUCT_ID_IDX |    53 |       |    21   (0)| 00:00:01 |     1 |    20 |
-----------------------------------------------------------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("PRODUCT_ID"=101)
```

### ・パーティションキーと非同一キーが含まれるクエリの実行
検索されるパーティションが限定され、さらに検索範囲内で索引が利用されるため効率的にアクセス可能です。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD') AND product_id = 101;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1927375225

-----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name                 | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                      |     1 |    48 |     1   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE                    |                      |     1 |    48 |     1   (0)| 00:00:01 |    17 |    17 |
|*  2 |   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES                |     1 |    48 |     1   (0)| 00:00:01 |    17 |    17 |
|*  3 |    INDEX RANGE SCAN                        | SALES_PRODUCT_ID_IDX |     1 |       |     1   (0)| 00:00:01 |    17 |    17 |
-----------------------------------------------------------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
   3 - access("PRODUCT_ID"=101)
```

## 3. 「グローバル・パーティション索引」の検証
インデックスキーに基づくクエリは、インデックス側のパーティションによって検索範囲が限定されるため効率的です。しかし、テーブルのパーティションキーと異なるため、テーブルの更新時にはパーティションが限定されず、インデックス全体が更新される可能性があります。また、テーブルのパーティション操作時は `UPDATE INDEX`句を指定しなければ索引が無効化されてしまい、指定した場合は索引の更新が完了するまでパーティション操作が完結しません。

### ・索引の作成
```
CREATE INDEX sales_global_idx ON sales(amount)
GLOBAL PARTITION BY RANGE (amount) (
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (2000),
    PARTITION p3 VALUES LESS THAN (MAXVALUE)
);
EXEC DBMS_STATS.GATHER_INDEX_STATS('test_user', 'sales_global_idx');
```

### ・インデックスキー（amount）が含まれるクエリの実行
索引側のパーティション設定により検索されるパーティションが限定され、さらに検索範囲内で索引が利用されるため効率的にアクセス可能です。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE amount = 1500;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1897535384

--------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                            |                  |    53 |  1113 |    51   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE                     |                  |    53 |  1113 |    51   (0)| 00:00:01 |     2 |     2 |
|   2 |   TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SALES            |    53 |  1113 |    51   (0)| 00:00:01 | ROWID | ROWID |
|*  3 |    INDEX RANGE SCAN                         | SALES_GLOBAL_IDX |    53 |       |     1   (0)| 00:00:01 |     2 |     2 |
--------------------------------------------------------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("AMOUNT"=1500)
```

### ・パーティションキー（sale_date）とインデックスキーが含まれるクエリの実行
テーブルと索引でパーティションキーが異なるため、どちらかの条件をもとに検索範囲が絞り込まれます。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD') AND amount = 1500;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4096232376

------------------------------------------------------------------------------------------------
| Id  | Operation              | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |       |     1 |    48 |     2   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE|       |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
|*  2 |   TABLE ACCESS FULL    | SALES |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "AMOUNT"=1500)
```

## 4. 「グローバル・非パーティション索引」の検証
インデックスキーに基づくクエリは効率的に実行されますが、パーティション化されたテーブルに対してはパーティションの利点が生かされず、テーブル全体にわたるインデックススキャンが発生する可能性があります。また、テーブルのパーティション操作時は `UPDATE INDEX`句を指定しなければ索引が無効化されてしまい、指定した場合は索引の更新が完了するまでパーティション操作が完結しません。

### ・索引の作成
```
CREATE INDEX sales_amount_idx ON sales(amount);
EXEC DBMS_STATS.GATHER_INDEX_STATS('test_user', 'sales_amount_idx');
```

### ・インデックスキー（amount）が含まれるクエリの実行
索引により絞り込みが実施されますが、パーティションによる検索範囲の絞り込みは実施されません。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE amount = 1500;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3109514936

-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name             | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                  |    53 |  1113 |    51   (0)| 00:00:01 |       |       |
|   1 |  TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SALES            |    53 |  1113 |    51   (0)| 00:00:01 | ROWID | ROWID |
|*  2 |   INDEX RANGE SCAN                         | SALES_AMOUNT_IDX |    53 |       |     1   (0)| 00:00:01 |       |       |
-------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - access("AMOUNT"=1500)
```

### ・パーティションキー（sale_date）が含まれるクエリの実行
パーティションにより検索範囲は限定されますが索引は使用されません。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4096232376

------------------------------------------------------------------------------------------------
| Id  | Operation              | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |       |     1 |    48 |     2   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE|       |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
|*  2 |   TABLE ACCESS FULL    | SALES |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
```

### ・パーティションキーとインデックスキーが含まれるクエリの実行
テーブルと索引のどちらかの条件をもとに検索範囲が絞り込まれます。
以下のパターンではパーティションにより検索範囲が限定されています。
```
EXPLAIN PLAN FOR
SELECT * FROM sales WHERE sale_date = TO_DATE('2023-03-15', 'YYYY-MM-DD') AND amount = 1500;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4096232376

------------------------------------------------------------------------------------------------
| Id  | Operation              | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |       |     1 |    48 |     2   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE|       |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
|*  2 |   TABLE ACCESS FULL    | SALES |     1 |    48 |     2   (0)| 00:00:01 |    17 |    17 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("SALE_DATE"=TO_DATE(' 2023-03-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "AMOUNT"=1500)
```

# まとめ
Oracle Databaseのパーティション機能は、大規模なデータセットを管理し、パフォーマンスを最適化するための強力なツールです。パーティションを利用することで、クエリのレスポンスタイムを短縮し、メンテナンス作業を効率化し、不要データの迅速な削除を可能にします。レンジ、リスト、ハッシュなど、さまざまなパーティション方式が提供され、使用するデータの特性に合わせて選択できます。また、索引を適切に設計することで、データアクセスの効率性をさらに向上させることが可能です。

本ドキュメントでの検証結果は、パーティションと索引の選択がクエリパフォーマンスに与える影響を明らかにしました。ローカル同一キー索引は、パーティションキーがクエリに含まれる場合に最も効率的です。一方、グローバルパーティション索引は、テーブルのパーティションキーと異なる検索キーに基づくクエリで有用ですが、更新時のオーバーヘッドが発生する可能性がある点に注意が必要です。

パーティション機能を最大限に活用するためには、データの特性を理解し、適切なパーティション戦略を策定することが重要です。また、索引の選択と設計は、システムのパフォーマンス要件とメンテナンスの容易さを考慮して行う必要があります。適切に設計されたパーティションと索引は、データベースのパフォーマンスとスケーラビリティを大幅に向上させることができるため、データベース管理者にとって不可欠な技術です。