Oracle 分区Oracle 分区置换实战指南
实战演练:历史数据归档与清理
场景设定
主表:T_ORDER_MAIN (订单主表),按月份范围分区。
目标:将 2023 年 1 月的数据(冷数据)从主表中“剥离”出来,归档到历史库,并在主表中快速清空该月数据。
3.1 环境准备
1. 创建分区主表
CREATE TABLE T_ORDER_MAIN (
order_id NUMBER,
order_date DATE,
customer_id NUMBER,
amount NUMBER(10,2),
region VARCHAR2(20)
)
PARTITION BY RANGE (order_date) (
PARTITION P_202212 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD')),
PARTITION P_202301 VALUES LESS THAN (TO_DATE('2023-02-01', 'YYYY-MM-DD')),
PARTITION P_202302 VALUES LESS THAN (TO_DATE('2023-03-01', 'YYYY-MM-DD')),
PARTITION P_MAX VALUES LESS THAN (MAXVALUE)
);
2. 创建本地索引
CREATE INDEX IDX_ORDER_DATE ON T_ORDER_MAIN(order_date) LOCAL;
CREATE INDEX IDX_CUST_ID ON T_ORDER_MAIN(customer_id) LOCAL;
3. 插入测试数据 (模拟 2023-01 的数据)
INSERT INTO T_ORDER_MAIN VALUES (1, TO_DATE('2023-01-15', 'YYYY-MM-DD'), 1001, 500.00, 'BJ');
INSERT INTO T_ORDER_MAIN VALUES (2, TO_DATE('2023-01-20', 'YYYY-MM-DD'), 1002, 300.00, 'SH');
COMMIT;
验证数据在分区 P_202301 中
SELECT COUNT(*) FROM T_ORDER_MAIN PARTITION (P_202301); -- 结果应为 2
3.2 第一步:创建“镜像”独立表
这是最关键的一步。我们不能手动 CREATE TABLE 然后逐个加字段,最稳妥的方法是利用 DBMS_METADATA 或直接基于分区定义创建。
-- 方法:基于主表结构创建一个空表,确保结构 100% 一致
CREATE TABLE T_ORDER_ARCHIVE_202301 AS
SELECT * FROM T_ORDER_MAIN WHERE 1=0;
-- 注意:CTAS (Create Table As Select) 不会复制索引和约束!
-- 我们需要手动补全索引和约束,或者使用 DBMS_METADATA 提取 DDL。
-- 为了演示清晰,这里手动创建匹配的索引(生产环境建议用脚本自动生成)
CREATE INDEX IDX_ARCH_DATE ON T_ORDER_ARCHIVE_202301(order_date);
CREATE INDEX IDX_ARCH_CUST ON T_ORDER_ARCHIVE_202301(customer_id);
-- 重要:如果主表有非空约束或主键,这里也必须加上,否则交换会失败。
-- 假设 order_id 是主键(简化演示,实际生产需严格对应)
ALTER TABLE T_ORDER_MAIN ADD CONSTRAINT PK_ORDER_MAIN PRIMARY KEY (order_id);
ALTER TABLE T_ORDER_ARCHIVE_202301 ADD CONSTRAINT PK_ORDER_ARCH PRIMARY KEY (order_id);
3.3 第二步:数据填充与校验
将目标分区的数据“逻辑”移动到独立表(此时还在主表里,只是我们准备交换)。技巧:通常我们是先把独立表准备好数据,然后交换进去。但在归档场景中,数据已经在主表分区里了。
策略调整:
创建一个空的独立表(结构已对齐)。
执行 不带 VALIDATE 的交换(如果确信数据干净)或者先导出数据再交换。
更安全的归档流程:
其实 EXCHANGE 是双向的。我们可以直接拿一个空表去交换有数据的分区。
交换后:主表分区变空了,独立表变满(拥有了原分区数据)。
-- 再次确认独立表是空的
SELECT COUNT(*) FROM T_ORDER_ARCHIVE_202301; -- 应为 0
-- 【核心操作】执行分区置换
-- WITHOUT VALIDATION: 告诉 Oracle“我保证数据是干净的,别检查了,直接换指针”。速度最快。
-- WITH VALIDATION: Oracle 会扫描独立表所有数据,确保都在分区范围内。如果数据量大,这会退化成全表扫描,失去意义。
-- 在本例中,独立表是空的,绝对干净,所以可以用 WITHOUT VALIDATION。
-- 如果是把外部数据表换进主表,必须确保数据符合分区范围。
ALTER TABLE T_ORDER_MAIN
EXCHANGE PARTITION P_202301
WITH TABLE T_ORDER_ARCHIVE_202301
WITHOUT VALIDATION
UPDATE GLOBAL INDEXES;
-- UPDATE GLOBAL INDEXES: 如果有全局索引,必须加这个子句,否则全局索引会变为 UNUSABLE。本地索引自动维护。
3.4 第三步:验证“魔术”效果
1. 检查主表分区 P_202301
SELECT COUNT(*) FROM T_ORDER_MAIN PARTITION (P_202301);
结果:0
2. 检查独立表
SELECT COUNT(*) FROM T_ORDER_ARCHIVE_202301;
结果:2 (数据瞬间“出现”在这个表里)
3. 检查主表整体
SELECT COUNT(*) FROM T_ORDER_MAIN;
结果:0 (因为其他分区本来就是空的,只有 P_202301 有数据且被换走了)
此时:
T_ORDER_MAIN 的 P_202301 分区现在是空的,可以接收新数据。
T_ORDER_ARCHIVE_202301 表现在包含了原来的历史数据。你可以对这个独立表进行压缩、传输到冷存储、或者直接 DROP TABLE (如果不需要归档)。




