语法介绍
-- 拆分 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 分区的拆分点。该值将成为第二个新分区的下边界。 | AT (TO_DATE('2022-07-01', 'YYYY-MM-DD'))
|
VALUES (value[, value]...)
| 用于 LIST 分区拆分 | 定义 LIST 分区拆分时,分配给第一个新分区的值列表。 | VALUES ('China', 'Singapore')
|
INTO (...)
| 必填 | 指定两个新分区的名称和可选的表空间。new_part1 包含拆分点之前的数据,new_part2 包含拆分点之后的数据。 | INTO (PARTITION p_h1, PARTITION p_h2)
|
TABLESPACE tablespace_name
| 可选 默认值:表的默认表空间 | 为新分区指定存储表空间。可为两个新分区指定不同或相同的表空间。 | TABLESPACE tbs_archive
|
使用示例
拆分范围(RANEG)分区
本示例演示如何将一个年度日志分区 p_2022 拆分为两个半年度分区 p_2022_h1 和 p_2022_h2。
环境准备
本步骤将创建一个按日志时间范围分区的表 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);
结果验证
验证原始分区被替换为两个新分区,且数据已正确分布。
-- 结构验证:确认新分区已创建,旧分区已消失
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);
结果验证
验证原始分区被替换为两个新分区,它们的值列表已正确分配,并且数据也随之迁移。
-- 结构验证:确认新分区已创建及其值列表
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。这是一个资源密集型操作,建议在业务低峰期执行。