レンジ (RANGE) またはリスト (LIST) パーティションを 2 つの新しいパーティションに分割します。この操作はデータを再編成するため、元に戻すことはできません。このコマンドを実行する前に、新しいパーティションの境界と名前を計画し、データをバックアップしてください。
概要
-- RANGE パーティションの分割
ALTER TABLE table_name SPLIT PARTITION partition_name
AT (range_part_value)
INTO
(
PARTITION new_part1
[TABLESPACE tablespace_name],
PARTITION new_part2
[TABLESPACE tablespace_name]
);
-- LIST パーティションの分割
ALTER TABLE table_name SPLIT PARTITION partition_name
VALUES (value[, value]...)
INTO
(
PARTITION new_part1
[TABLESPACE tablespace_name],
PARTITION new_part2
[TABLESPACE tablespace_name]
);
パラメーター
パラメーター | 必須 | 説明 | 例 |
table_name
| はい | ターゲットのパーティションテーブルの名前。 | log_archives
|
partition_name
| はい | 分割する既存のパーティションの名前。 | p_2022
|
AT (range_part_value)
| RANGE パーティションの分割に必要
| RANGE パーティションの分割点を定義します。この値は、2 番目の新しいパーティションの下限になります。
| AT (TO_DATE('2022-07-01', 'YYYY-MM-DD'))
|
VALUES (value[, value]...)
| LIST パーティションの分割に必要
| LIST パーティションを分割するときに、最初の新しいパーティションに割り当てる値のリストを定義します。
| VALUES ('China', 'Singapore')
|
INTO (...)
| はい | 2 つの新しいパーティションの名前と、オプションの表領域を指定します。new_part1 には分割点より前のデータが含まれ、new_part2 には分割点より後のデータが含まれます。 | INTO (PARTITION p_h1, PARTITION p_h2)
|
TABLESPACE tablespace_name
| いいえ デフォルト値: テーブルのデフォルトの表領域
| 新しいパーティションのストレージ表領域を指定します。2 つの新しいパーティションに、異なるまたは同じ表領域を指定できます。 | TABLESPACE tbs_archive
|
注意事項
テーブルのオーナーであるか、テーブルに対する ALTER 権限を持っている必要があります。
SPLIT PARTITION は、テーブルレベルの排他ロックである AccessExclusiveLock を取得します。このロックは、テーブルに対するすべてのデータ操作言語 (DML) とほとんどのデータ定義言語 (DDL) の操作をブロックします。このコマンドは、オフピークの時間帯に実行し、十分なタイムウィンドウを確保してください。
分割点は有効である必要があります:
例
レンジ (RANGE) パーティションの分割
この例では、p_2022 という名前の年間ログパーティションを、p_2022_h1 と p_2022_h2 という名前の 2 つの半期パーティションに分割する方法を示します。
環境の準備
このステップでは、時間範囲でパーティション化された log_archives という名前のテーブルを作成し、分割点をまたぐデータを挿入します。
-- パーティションテーブルを作成します。
CREATE TABLE log_archives (
log_id INT NOT NULL,
log_time DATE NOT NULL
)
PARTITION BY RANGE (log_time) (
PARTITION p_2022 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD'))
);
INSERT INTO log_archives VALUES (1, TO_DATE('2022-01-10', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (2, TO_DATE('2022-02-15', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (3, TO_DATE('2022-03-20', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (4, TO_DATE('2022-05-05', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (5, TO_DATE('2022-06-25', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (6, TO_DATE('2022-07-15', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (7, TO_DATE('2022-08-01', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (8, TO_DATE('2022-10-30', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (9, TO_DATE('2022-11-11', 'YYYY-MM-DD'));
INSERT INTO log_archives VALUES (10, TO_DATE('2022-12-24', 'YYYY-MM-DD'));
事前チェックの実行
パーティションを分割する前に、データがバックアップされていることを確認し、元のパーティションが存在するかどうかを確認します。
-- 重要: パーティションを分割する前に、関連データがバックアップされていることを確認してください。
SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'LOG_ARCHIVES';
コマンドの実行
2022-07-01 を分割点として使用し、SPLIT PARTITION コマンドを実行します。
ALTER TABLE log_archives SPLIT PARTITION p_2022
AT (TO_DATE('2022-07-01', 'YYYY-MM-DD'))
INTO (PARTITION p_2022_h1, PARTITION p_2022_h2);
結果の検証
元のパーティションが 2 つの新しいパーティションに置き換えられ、データが正しく分散されていることを確認します。
-- 構造の検証: 新しいパーティションが作成され、古いパーティションが削除されたことを確認します。
SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'LOG_ARCHIVES';
-- クエリ結果には p_2022_h1 と p_2022_h2 が含まれますが、p_2022 は含まれません。
-- データの検証: データが分割点に基づいて分散されていることを確認します。
SELECT COUNT(*) FROM log_archives PARTITION (p_2022_h1); -- 結果は 5 になるはずです。
SELECT COUNT(*) FROM log_archives PARTITION (p_2022_h2); -- 結果は 5 になるはずです。
リスト (LIST) パーティションの分割
この例では、複数の国と地域を含む p_asia という名前のアジアの売上パーティションを、p_china という名前の独立した中国パーティションと、その他のアジアの国と地域のための p_asia_others という名前の別のパーティションに分割する方法を示します。
環境の準備
このステップでは、販売地域のリストでパーティション化された sales_by_region という名前のテーブルを作成します。
-- パーティションテーブルを作成します。
CREATE TABLE sales_by_region (
sale_id INT,
country VARCHAR2(20)
)
PARTITION BY LIST (country) (
PARTITION p_asia VALUES ('China', 'Japan', 'Korea', 'Singapore')
);
INSERT INTO sales_by_region VALUES (101, 'China');
INSERT INTO sales_by_region VALUES (102, 'China');
INSERT INTO sales_by_region VALUES (201, 'Japan');
INSERT INTO sales_by_region VALUES (301, 'Korea');
INSERT INTO sales_by_region VALUES (401, 'Singapore');
事前チェックの実行
p_asia パーティションが存在するかどうかを確認し、そのデータ分布を確認します。
SELECT PARTITION_NAME, HIGH_VALUE FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'SALES_BY_REGION';
SELECT country, COUNT(*) FROM sales_by_region GROUP BY country;
コマンドの実行
VALUES 句を使用して、p_asia パーティションから 'China' のデータを p_china という名前の新しいパーティションに分割します。
ALTER TABLE sales_by_region SPLIT PARTITION p_asia
VALUES ('China')
INTO (PARTITION p_china, PARTITION p_asia_others);
結果の検証
元のパーティションが 2 つの新しいパーティションに置き換えられ、それらの値リストが正しく割り当てられ、データがそれに応じて移行されていることを確認します。
-- 構造の検証: 新しいパーティションとその値リストが作成されたことを確認します。
SELECT PARTITION_NAME, HIGH_VALUE FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'SALES_BY_REGION';
-- クエリ結果には以下が含まれるはずです:
-- P_CHINA, 'China'
-- P_ASIA_OTHERS, 'Japan', 'Korea', 'Singapore'
-- データの検証: データが新しいパーティションに分散されていることを確認します。
SELECT COUNT(*) FROM sales_by_region PARTITION (p_china); -- 結果は 2 になるはずです。
SELECT COUNT(*) FROM sales_by_region PARTITION (p_asia_others); -- 結果は 3 になるはずです。
よくある質問
Q1: なぜ ORA-14080: partition cannot be split というエラーが表示されるのですか?
このエラーは通常、定義した分割点が無効なために発生します。RANGE パーティションの場合、AT 句の値は、分割されるパーティションの上限と下限の間にある必要があります。LIST パーティションの場合、VALUES 句の値のリストは、分割されるパーティションの値リストの空でない適切なサブセットである必要があります。
Q2: なぜ ORA-14078: partition name is already in use というエラーが表示されるのですか?
このエラーは、INTO 句で指定した新しいパーティション名が、テーブル内の別のパーティションですでに使用されているために発生します。テーブル内で一意の名前に名前を変更してください。
Q3: なぜ SPLIT PARTITION は遅いのですか?
この操作には、物理データの再編成とコピーが含まれます。実行時間はパーティション内のデータ量に比例し、大量の I/O を生成します。これはリソースを大量に消費する操作です。この操作はオフピークの時間帯に実行してください。