Oracleパーティションテーブルの確認と管理方法【レンジ・リスト・ハッシュ対応】

当ページのリンクには広告が含まれています。

大量データのテーブルを高速化・管理しやすくするOracle Partitioning。本記事ではパーティションテーブルの確認方法から、レンジ・リスト・ハッシュパーティションの作成、追加・削除・マージまで現場で使う操作を完全解説します。

目次

1. パーティションテーブルとは {#about}

パーティションとは1つのテーブルを複数の物理領域(パーティション)に分割して管理する機能です。

メリット:

  • WHERE句でパーティション列を指定するとスキャン範囲が絞られて高速化
  • 古いデータをパーティション単位でDROP/TRUNCATEできる(DELETE不要)
  • パーティション単位でメンテナンス(バックアップ・インデックス再構築)が可能

パーティションの種類:

種類分割基準典型的な用途
レンジ(RANGE)値の範囲(日付・数値)年次・月次データ
リスト(LIST)値のリスト(地域・区分)地域別・カテゴリ別
ハッシュ(HASH)ハッシュ値(自動均等分散)均等分散させたい場合
コンポジット上記の組み合わせ大規模DWH

2. パーティション情報の確認SQL {#check-partition}

パーティションテーブルの一覧を確認

-- パーティションテーブルのみを確認
SELECT TABLE_NAME, PARTITIONING_TYPE, PARTITION_COUNT, STATUS
FROM USER_PART_TABLES
ORDER BY TABLE_NAME;

出力例:

TABLE_NAME          PARTITIONING_TYPE  PARTITION_COUNT  STATUS
------------------  -----------------  ---------------  ------
SALES               RANGE              24               OK
CUSTOMERS           LIST               5                OK
LOG_HISTORY         RANGE              36               OK

パーティションの詳細を確認

-- テーブルの各パーティション情報
SELECT
    PARTITION_NAME,
    PARTITION_POSITION,
    HIGH_VALUE,         -- パーティションの上限値
    NUM_ROWS,           -- 行数(統計情報から)
    BLOCKS,
    LAST_ANALYZED
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = 'SALES'
ORDER BY PARTITION_POSITION;

出力例:

PARTITION_NAME  PARTITION_POSITION  HIGH_VALUE              NUM_ROWS  LAST_ANALYZED
--------------  ------------------  ----------------------  --------  ----------------
P2024_01        1                   TO_DATE('2024-02-01')   1250000   2024-02-01 02:00
P2024_02        2                   TO_DATE('2024-03-01')   1180000   2024-03-01 02:00
P2026_04        27                  TO_DATE('2026-05-01')    890000   2026-05-01 02:00
P_MAX           28                  MAXVALUE                      0   (null)

パーティションインデックスの確認

-- パーティションインデックスを確認
SELECT INDEX_NAME, PARTITIONING_TYPE, LOCALITY, ALIGNMENT
FROM USER_PART_INDEXES
WHERE TABLE_NAME = 'SALES';
  • LOCALITY = LOCAL:テーブルと同じパーティション構成のインデックス(推奨)
  • LOCALITY = GLOBAL:独立したパーティション構成のインデックス

3. レンジパーティションの作成と管理 {#range-partition}

日付や数値の範囲でパーティションを分割する最も一般的な方式です。

月次レンジパーティションの作成

CREATE TABLE SALES (
    SALE_ID     NUMBER,
    SALE_DATE   DATE NOT NULL,
    CUSTOMER_ID NUMBER,
    AMOUNT      NUMBER(12, 2),
    REGION      VARCHAR2(20)
)
PARTITION BY RANGE (SALE_DATE) (
    PARTITION P2024_01 VALUES LESS THAN (DATE '2024-02-01'),
    PARTITION P2024_02 VALUES LESS THAN (DATE '2024-03-01'),
    PARTITION P2024_03 VALUES LESS THAN (DATE '2024-04-01'),
    PARTITION P2024_Q2 VALUES LESS THAN (DATE '2024-07-01'),  -- 四半期でまとめることも可
    PARTITION P_MAX    VALUES LESS THAN (MAXVALUE)             -- 上限なし(必須)
);

VALUES LESS THAN (MAXVALUE) を最後に付けないと、上限を超えるデータのINSERT時にエラーが発生します。

月次パーティションを自動作成するINTERVALパーティション(11g以降)

-- INTERVALパーティション:月が増えるたびに自動でパーティションが作られる
CREATE TABLE SALES_INTERVAL (
    SALE_ID     NUMBER,
    SALE_DATE   DATE NOT NULL,
    AMOUNT      NUMBER(12, 2)
)
PARTITION BY RANGE (SALE_DATE)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))  -- 1ヶ月単位で自動作成
(
    PARTITION P_INIT VALUES LESS THAN (DATE '2024-01-01')  -- 最初の1つだけ必要
);

INTERVALパーティションは自動で月次パーティションが追加されるため、ALTER TABLE ADD PARTITION が不要になります。


4. リストパーティションの作成と管理 {#list-partition}

特定の値のリストでパーティションを分割します。地域・区分コードなどに適しています。

CREATE TABLE CUSTOMERS (
    CUSTOMER_ID NUMBER,
    REGION      VARCHAR2(20) NOT NULL,
    NAME        VARCHAR2(100),
    CREATED_AT  DATE
)
PARTITION BY LIST (REGION) (
    PARTITION P_EAST   VALUES ('東京', '神奈川', '千葉', '埼玉'),
    PARTITION P_KANSAI VALUES ('大阪', '京都', '兵庫', '奈良'),
    PARTITION P_OTHER  VALUES (DEFAULT)  -- 上記以外を全て格納
);

VALUES (DEFAULT) を付けることで未定義の値が来ても格納できます(Oracleの推奨)。


5. ハッシュパーティションの作成 {#hash-partition}

指定列のハッシュ値でデータを均等に分散させます。分割基準が特になく、I/O負荷を分散させたい場合に使います。

CREATE TABLE LOG_DATA (
    LOG_ID   NUMBER,
    USER_ID  NUMBER NOT NULL,
    LOG_MSG  VARCHAR2(4000),
    LOG_TIME DATE
)
PARTITION BY HASH (USER_ID)
PARTITIONS 8  -- 8つのパーティションに均等分散
STORE IN (TBS1, TBS2, TBS3, TBS4, TBS5, TBS6, TBS7, TBS8);  -- 各テーブルスペースを指定

6. パーティションの追加・削除・マージ・分割 {#manage-partition}

パーティションの追加(ADD PARTITION)

-- レンジパーティションに新しい月を追加(MAXVALUE の前に追加が必要)
-- MAXVALUE がある場合は SPLIT PARTITION で分割する方法を使う

-- MAXVALUE がない場合の追加
ALTER TABLE SALES ADD PARTITION P2026_05
VALUES LESS THAN (DATE '2026-06-01');

-- リストパーティションに値を追加
ALTER TABLE CUSTOMERS
ADD PARTITION P_HOKKAIDO VALUES ('北海道', '青森', '秋田');

MAXVALUE パーティションがある場合の月次追加(SPLIT)

-- P_MAX を分割して新しい月パーティションを作成
ALTER TABLE SALES SPLIT PARTITION P_MAX
AT (DATE '2026-06-01')
INTO (
    PARTITION P2026_05,
    PARTITION P_MAX
);

パーティションのTRUNCATE(古いデータを高速削除)

-- 特定パーティションのデータを高速削除(テーブル構造は残る)
ALTER TABLE SALES TRUNCATE PARTITION P2024_01;

DELETEより圧倒的に高速。UNDOも生成しないため大量データの削除に最適。

パーティションのDROP(パーティションごと削除)

-- パーティションとそのデータを完全に削除
ALTER TABLE SALES DROP PARTITION P2024_01;

-- INTERVALパーティションの場合
ALTER TABLE SALES DROP PARTITION FOR (DATE '2024-01-15');

パーティションのMERGE(2つを1つに統合)

-- 隣接する2つのパーティションを1つにまとめる
ALTER TABLE SALES MERGE PARTITIONS P2024_01, P2024_02
INTO PARTITION P2024_Q1;

7. パーティションプルーニング(クエリの高速化) {#pruning}

パーティション列をWHERE句に指定することで、該当パーティションだけをスキャンする「パーティションプルーニング」が効きます。

実行計画でパーティションプルーニングを確認

EXPLAIN PLAN FOR
SELECT * FROM SALES
WHERE SALE_DATE BETWEEN DATE '2026-04-01' AND DATE '2026-04-30';

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

プルーニングが効いている場合の出力:

-----------------------------------------------------------------------------------
| Id | Operation             | Name  | Rows | Pstart | Pstop |
-----------------------------------------------------------------------------------
|  0 | SELECT STATEMENT      |       |      |        |       |
|  1 |  PARTITION RANGE SINGLE |     |      |     27 |    27 |  ← 特定パーティションのみ
|  2 |   TABLE ACCESS FULL   | SALES |      |     27 |    27 |
-----------------------------------------------------------------------------------
  • Pstart と Pstop が同じ番号:特定パーティションのみスキャン
  • Pstart=1, Pstop=28:全パーティションスキャン(プルーニング失敗)

プルーニングが効かない典型的なパターン:

-- NG:パーティション列に関数を使う
SELECT * FROM SALES WHERE TRUNC(SALE_DATE, 'MM') = DATE '2026-04-01';

-- OK:パーティション列をそのまま比較
SELECT * FROM SALES WHERE SALE_DATE >= DATE '2026-04-01'
                      AND SALE_DATE < DATE '2026-05-01';

8. パーティションのメンテナンス操作 {#maintenance}

パーティション単位で統計情報を収集

-- 特定パーティションの統計情報を更新
EXEC DBMS_STATS.GATHER_TABLE_STATS(
    ownname    => 'SCOTT',
    tabname    => 'SALES',
    partname   => 'P2026_04',
    granularity => 'PARTITION'
);

パーティション単位でインデックスを再構築

-- パーティションのインデックスを再構築
ALTER INDEX IDX_SALES_DATE REBUILD PARTITION P2026_04;

グローバルインデックスの再構築(DROPやTRUNCATEの後)

-- パーティションのDROP/TRUNCATE後にグローバルインデックスが無効になる場合
ALTER TABLE SALES DROP PARTITION P2024_01
UPDATE GLOBAL INDEXES;  -- これを付けるとグローバルインデックスを自動維持(処理は重い)

-- または事後にREBUILD
ALTER INDEX IDX_SALES_GLOBAL REBUILD;

9. まとめ:パーティション管理チェックリスト {#summary}

設計時
□ パーティション列は NULL を含まない列を選ぶ
□ レンジパーティションは必ず MAXVALUE(または VALUES (DEFAULT))を末尾に付ける
□ 月次追加が必要ならINTERVALパーティションで自動化を検討
□ グローバルインデックスより LOCAL インデックスを優先

運用時
□ 月次バッチ:新しい月のパーティションを事前に ADD または SPLIT で追加
□ 古いデータは DELETE より TRUNCATE PARTITION / DROP PARTITION を使う
□ DROP/TRUNCATE後はグローバルインデックスの状態を確認・再構築
□ 月次統計情報収集はパーティション単位で実施して効率化

クエリ確認
□ 実行計画で Pstart/Pstop を確認してプルーニングが効いているか確認
□ WHERE句のパーティション列に関数・型変換を使わない

関連記事:

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ITの事や自分の経験談など綴っていきたいと思っています。

コメント

コメントする

CAPTCHA


目次