【Oracle】パーティションテーブルの作成・管理完全ガイド|RANGE・LIST・HASH・INTERVAL・分割と結合まで解説

【Oracle】パーティションテーブルの作成・管理完全ガイド|RANGE・LIST・HASH・INTERVAL・分割と結合まで解説 Oracle

テーブルの行数が数千万〜数億行に達すると、フルスキャンやインデックスアクセスだけでは限界が来ます。Oracleのパーティションテーブルは、1つの論理テーブルを複数の物理セグメント(パーティション)に分割して格納する仕組みで、大規模データの検索性能・メンテナンス効率・可用性を大幅に向上させます。本記事では主要なパーティション方式の作成方法から、運用で必要なパーティション操作まで体系的に解説します。

この記事でわかること

  • パーティションテーブルのメリットと使いどころ
  • RANGE パーティション(日付・数値の範囲で分割)の作成方法
  • LIST パーティション(値リストで分割)の作成方法
  • HASH パーティション(ハッシュで均等分散)の作成方法
  • INTERVAL パーティション(自動作成)の作成方法
  • コンポジットパーティション(RANGE-LIST 等の2段分割)
  • パーティションの追加・削除・TRUNCATE・結合・交換の操作
  • パーティション情報の確認SQL
  • パーティションプルーニングの仕組み
スポンサーリンク

パーティションテーブルのメリット

メリット 説明
検索性能の向上 WHERE句の条件に合致するパーティションだけをスキャンする(パーティションプルーニング)
メンテナンス効率 古いデータのパーティションだけを DROP/TRUNCATE でき、DELETE より圧倒的に高速
並列処理の効率化 パーティション単位で並列スキャン・並列DMLが可能
バックアップの柔軟性 パーティション単位で表領域を分けてバックアップ・リストアできる
可用性の向上 1つのパーティションが破損しても他のパーティションは参照可能

RANGE パーティション ── 範囲で分割する

最も一般的なパーティション方式です。日付や数値の範囲を基準にデータを分割します。ログテーブルや売上テーブルなど、日付ベースのデータに最適です。

RANGE パーティション ── 月単位で分割する
CREATE TABLE sales (
    sale_id    NUMBER,
    sale_date  DATE,
    amount     NUMBER,
    customer_id NUMBER
)
PARTITION BY RANGE (sale_date) (
    PARTITION p_2025_01 VALUES LESS THAN (TO_DATE('2025-02-01', 'YYYY-MM-DD')),
    PARTITION p_2025_02 VALUES LESS THAN (TO_DATE('2025-03-01', 'YYYY-MM-DD')),
    PARTITION p_2025_03 VALUES LESS THAN (TO_DATE('2025-04-01', 'YYYY-MM-DD')),
    PARTITION p_2025_04 VALUES LESS THAN (TO_DATE('2025-05-01', 'YYYY-MM-DD')),
    PARTITION p_max     VALUES LESS THAN (MAXVALUE)  -- どの範囲にも入らないデータ用
);
MAXVALUE パーティションの役割
VALUES LESS THAN (MAXVALUE) を定義しておくと、想定外の日付のデータもエラーにならず格納されます。ただしMAXVALUEパーティションがあると、新しいパーティションの追加時に SPLIT が必要になるため、後述の INTERVAL パーティションの利用も検討してください。
RANGE パーティション ── 数値範囲で分割する
CREATE TABLE order_archive (
    order_id   NUMBER,
    order_date DATE,
    status     VARCHAR2(20)
)
PARTITION BY RANGE (order_id) (
    PARTITION p_0_1m    VALUES LESS THAN (1000000),
    PARTITION p_1m_2m   VALUES LESS THAN (2000000),
    PARTITION p_2m_3m   VALUES LESS THAN (3000000),
    PARTITION p_max     VALUES LESS THAN (MAXVALUE)
);

LIST パーティション ── 値のリストで分割する

特定の値(地域コード・ステータス・カテゴリ等)でデータを分割します。値の種類が少なく明確に決まっている場合に適しています。

LIST パーティション ── 地域コードで分割する
CREATE TABLE customers (
    customer_id NUMBER,
    name        VARCHAR2(100),
    region      VARCHAR2(20)
)
PARTITION BY LIST (region) (
    PARTITION p_kanto  VALUES ('東京', '神奈川', '千葉', '埼玉'),
    PARTITION p_kansai VALUES ('大阪', '京都', '兵庫'),
    PARTITION p_other  VALUES (DEFAULT)  -- 上記以外の値を受け入れるデフォルトパーティション
);

HASH パーティション ── ハッシュ値で均等分散する

パーティションキーのハッシュ値でデータを均等に分散します。明確な範囲やリストがない場合、または特定のパーティションにデータが偏るのを防ぎたい場合に使います。

HASH パーティション ── 4分割で作成する
CREATE TABLE access_log (
    log_id     NUMBER,
    user_id    NUMBER,
    access_time TIMESTAMP,
    url        VARCHAR2(500)
)
PARTITION BY HASH (user_id)
PARTITIONS 4;  -- 4つのパーティションに均等分散
-- パーティション名は SYS_P#### のように自動生成される
HASH パーティション ── パーティション名を明示する
CREATE TABLE access_log (
    log_id     NUMBER,
    user_id    NUMBER,
    access_time TIMESTAMP,
    url        VARCHAR2(500)
)
PARTITION BY HASH (user_id) (
    PARTITION p_hash_1,
    PARTITION p_hash_2,
    PARTITION p_hash_3,
    PARTITION p_hash_4
);
HASH パーティションの数は2のべき乗が推奨
パーティション数を2, 4, 8, 16 のように2のべき乗にすると、ハッシュ分散が最も均等になります。3や5のような数では偏りが生じる可能性があります。

INTERVAL パーティション ── パーティションを自動作成する

RANGE パーティションの拡張で、指定した間隔(月・日・数値)のパーティションがデータ挿入時に自動的に作成されます。事前にパーティションを定義する手間がなくなるため、日付ベースのテーブルで特に便利です。

INTERVAL パーティション ── 月単位で自動作成
CREATE TABLE event_log (
    event_id   NUMBER,
    event_date DATE,
    event_type VARCHAR2(50),
    detail     VARCHAR2(500)
)
PARTITION BY RANGE (event_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))  -- 1ヶ月間隔で自動作成
(
    PARTITION p_initial VALUES LESS THAN (TO_DATE('2025-01-01', 'YYYY-MM-DD'))
);
-- 2025-03-15 のデータをINSERTすると、2025-03 用のパーティションが自動生成される
INTERVAL パーティション ── 日単位で自動作成
CREATE TABLE daily_metrics (
    metric_date DATE,
    metric_name VARCHAR2(100),
    value       NUMBER
)
PARTITION BY RANGE (metric_date)
INTERVAL (NUMTODSINTERVAL(1, 'DAY'))  -- 1日間隔で自動作成
(
    PARTITION p_initial VALUES LESS THAN (TO_DATE('2025-01-01', 'YYYY-MM-DD'))
);

コンポジットパーティション ── 2段階で分割する

1つのパーティションキーだけでは不十分な場合、2段階の分割(コンポジットパーティション)を使います。例えば「月ごとにRANGE分割 → さらに地域ごとにLIST分割」といった構成が可能です。

RANGE-LIST コンポジットパーティション
CREATE TABLE sales_detail (
    sale_id    NUMBER,
    sale_date  DATE,
    region     VARCHAR2(20),
    amount     NUMBER
)
PARTITION BY RANGE (sale_date)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE (
    SUBPARTITION sp_east  VALUES ('東京', '神奈川'),
    SUBPARTITION sp_west  VALUES ('大阪', '京都'),
    SUBPARTITION sp_other VALUES (DEFAULT)
)
(
    PARTITION p_2025_q1 VALUES LESS THAN (TO_DATE('2025-04-01', 'YYYY-MM-DD')),
    PARTITION p_2025_q2 VALUES LESS THAN (TO_DATE('2025-07-01', 'YYYY-MM-DD')),
    PARTITION p_2025_q3 VALUES LESS THAN (TO_DATE('2025-10-01', 'YYYY-MM-DD')),
    PARTITION p_2025_q4 VALUES LESS THAN (TO_DATE('2026-01-01', 'YYYY-MM-DD'))
);
-- 各パーティション内に sp_east / sp_west / sp_other の3サブパーティションが作られる
コンポジットの組み合わせ 用途例
RANGE – LIST 月ごと × 地域ごと
RANGE – HASH 月ごと × ユーザーIDで均等分散
LIST – HASH カテゴリごと × IDで均等分散
LIST – LIST 地域ごと × ステータスごと

パーティションの操作(追加・削除・TRUNCATE・結合・交換)

パーティションの追加

ADD PARTITION ── 新しいパーティションを追加する
-- RANGE パーティションに新しい月を追加
ALTER TABLE sales
ADD PARTITION p_2025_05 VALUES LESS THAN (TO_DATE('2025-06-01', 'YYYY-MM-DD'));

-- LIST パーティションに新しい値のリストを追加
ALTER TABLE customers
ADD PARTITION p_tohoku VALUES ('宮城', '岩手', '秋田');

パーティションの削除

DROP PARTITION ── パーティションごとデータを削除
-- パーティションとデータを一括削除(DELETE より圧倒的に高速)
ALTER TABLE sales DROP PARTITION p_2025_01;

-- グローバルインデックスを保持したまま削除する場合
ALTER TABLE sales DROP PARTITION p_2025_01 UPDATE INDEXES;

パーティションの TRUNCATE

TRUNCATE PARTITION ── データだけ削除(構造は残す)
-- パーティション構造を残したままデータだけ即座に削除
ALTER TABLE sales TRUNCATE PARTITION p_2025_01;

-- グローバルインデックスを保持する場合
ALTER TABLE sales TRUNCATE PARTITION p_2025_01 UPDATE INDEXES;

パーティションの分割(SPLIT)

SPLIT PARTITION ── 1つのパーティションを2つに分割
-- MAXVALUE パーティションを分割して新しい月を追加
ALTER TABLE sales SPLIT PARTITION p_max
    AT (TO_DATE('2025-06-01', 'YYYY-MM-DD'))
    INTO (
        PARTITION p_2025_05,
        PARTITION p_max
    );

パーティションの結合(MERGE)

MERGE PARTITIONS ── 2つのパーティションを1つに結合
-- 隣接する2つのパーティションを結合
ALTER TABLE sales MERGE PARTITIONS p_2025_01, p_2025_02
    INTO PARTITION p_2025_q1;

パーティション交換(EXCHANGE)

EXCHANGE PARTITION ── パーティションとテーブルを入れ替える
-- 事前にロード済みのステージングテーブルとパーティションを瞬時に入れ替え
ALTER TABLE sales
    EXCHANGE PARTITION p_2025_03
    WITH TABLE sales_staging_2025_03
    INCLUDING INDEXES
    WITHOUT VALIDATION;
-- テーブルのデータとパーティションのデータがメタデータレベルで入れ替わる
-- 大量データのロードを無停止で行うテクニック
EXCHANGE PARTITION の活用
ステージングテーブルにデータをロードし、検証後にパーティション交換するパターンは、大規模データの「無停止切り替え」で広く使われるテクニックです。交換自体はメタデータの書き換えのみなので瞬時に完了します。

パーティション情報の確認SQL

パーティション一覧と行数を確認する
-- テーブルのパーティション一覧
SELECT
    partition_name,
    high_value,           -- パーティションの上限値(RANGE/LISTの場合)
    partition_position,   -- パーティションの順番
    num_rows,             -- 行数(統計収集後に反映)
    blocks,               -- 使用ブロック数
    last_analyzed         -- 最終統計収集日時
FROM user_tab_partitions
WHERE table_name = 'SALES'
ORDER BY partition_position;
サブパーティション一覧を確認する
SELECT
    partition_name,
    subpartition_name,
    subpartition_position,
    num_rows,
    last_analyzed
FROM user_tab_subpartitions
WHERE table_name = 'SALES_DETAIL'
ORDER BY partition_name, subpartition_position;
パーティションテーブルかどうかを確認する
SELECT
    table_name,
    partitioned     -- YES=パーティションテーブル, NO=通常テーブル
FROM user_tables
WHERE table_name = 'SALES';

パーティションプルーニングの仕組み

パーティションプルーニングは、WHERE句の条件に基づいて不要なパーティションを自動的にスキップする最適化です。パーティションテーブルの性能メリットの大部分はこの仕組みに依存しています。

パーティションプルーニングの例
-- sale_date が 2025-03 に限定されるため、p_2025_03 パーティションだけスキャンされる
SELECT * FROM sales
WHERE sale_date BETWEEN TO_DATE('2025-03-01', 'YYYY-MM-DD')
                     AND TO_DATE('2025-03-31', 'YYYY-MM-DD');

-- 実行計画で確認する
EXPLAIN PLAN FOR
SELECT * FROM sales
WHERE sale_date >= TO_DATE('2025-03-01', 'YYYY-MM-DD')
  AND sale_date <  TO_DATE('2025-04-01', 'YYYY-MM-DD');

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- 「PARTITION RANGE SINGLE」や「Pstart=3 Pstop=3」が表示されればプルーニングが効いている
プルーニングが効かないケース

  • パーティションキー列に関数を適用している(例: WHERE TRUNC(sale_date) = ...
  • パーティションキー列で暗黙の型変換が発生している
  • WHERE句にパーティションキー列の条件がない

実行計画の Pstart/Pstop 列でプルーニング範囲を確認し、想定どおりか検証してください。実行計画の読み方は「【Oracle】SQLの実行計画を確認する方法」を参照してください。

パーティション方式の選び方

方式 分割基準 適したデータ 自動パーティション作成
RANGE 値の範囲(日付・数値) ログ・売上・履歴データ 不可(手動追加)
INTERVAL RANGEの自動版 日付ベースのデータ(月次・日次) 可能(INSERT時に自動作成)
LIST 値のリスト 地域・カテゴリ・ステータス 不可(手動追加)
HASH ハッシュ値 偏りなく分散したいデータ 不可(作成時に固定)

まとめ

パーティションテーブルは大規模データのパフォーマンスとメンテナンス効率を劇的に改善する、Oracleの重要機能です。

  • RANGE:日付・数値の範囲で分割する最も一般的な方式。ログや売上データに最適
  • LIST:地域コードやカテゴリなど、離散的な値で分割する方式
  • HASH:ハッシュで均等分散する方式。パーティション数は2のべき乗が推奨
  • INTERVAL:RANGEの拡張で、INSERT時にパーティションが自動作成される。日付ベースのテーブルに最適
  • コンポジット:RANGE-LIST やRANGE-HASH等の2段階分割で、より細かい管理が可能
  • パーティション操作:ADD / DROP / TRUNCATE / SPLIT / MERGE / EXCHANGE で柔軟に管理。EXCHANGE PARTITIONは大量データの無停止切り替えに活用
  • パーティションプルーニング:WHERE句にパーティションキーの条件があれば自動的に不要なパーティションがスキップされる。キー列への関数適用は避ける