exchange partition 是清理tb级历史数据真正“快”的路径,因其仅交换元数据、不走dml流程、不生成大量redo/undo、不长时间锁表、不依赖索引扫描;而delete where sale_date会触发全表扫描、产生巨量日志、严重阻塞并发、耗时数小时甚至更久。
直接用 alter table ... exchange partition 配合 drop table,是清理 tb 级历史数据唯一真正“快”的路径——它不走 dml 流程,不生成大量 redo/undo,不锁表太久,也不依赖索引扫描。
为什么不能直接 DELETE 或 TRUNCATE?
对 TB 级分区表执行 DELETE WHERE sale_date 会:产生海量 undo 和归档日志;长时间持有行锁甚至表锁;可能触发回滚段溢出或归档风暴;即使加并行 hint,仍需全表扫描+索引维护。而 <code>TRUNCATE TABLE 只能清整表,无法精准切掉“2022 年及以前”的分区数据。
EXCHANGE PARTITION 清理的完整链路
核心不是“删”,而是“换出来再扔”。必须保证三张表结构完全一致(含约束、默认值、NOT NULL 属性),且目标分区与临时表无数据冲突:
- 先查出要清理的分区名:
SELECT partition_name FROM user_tab_partitions WHERE table_name = 'SALES' AND high_value LIKE '%2022%' - 建空临时表:
CREATE TABLE sales_2022_temp AS SELECT * FROM sales WHERE 1=0(注意:必须用AS SELECT复制 NOT NULL 和默认值,不能只用CREATE TABLE ... LIKE) - 执行交换:
ALTER TABLE sales EXCHANGE PARTITION p_2022 WITH TABLE sales_2022_temp INCLUDING INDEXES WITHOUT VALIDATION(WITHOUT VALIDATION跳过数据一致性校验,省时;但要求你确认源分区和临时表结构/约束绝对匹配) - 立刻删临时表:
DROP TABLE sales_2022_temp(此时原分区数据已物理移出主表,删除的是独立段,毫秒级)
本地索引 vs 全局索引:重建时机很关键
如果分区表有本地索引(LOCAL),交换后自动跟随分区转移,无需额外操作;但若有全局索引(GLOBAL),交换会导致其失效(STATUS = UNUSABLE),必须在交换后立即重建:
- 查全局索引:
SELECT index_name FROM user_indexes WHERE table_name = 'SALES' AND partitioned = 'NO' - 重建命令:
ALTER INDEX sales_global_idx REBUILD ONLINE(加ONLINE避免阻塞业务查询) - 千万别等所有分区交换完再统一重建——每交换一个分区,对应全局索引就多一分 unusable 风险,查询可能报错
容易被忽略的坑:HIGH_VALUE 解析和时间边界
分区高值(HIGH_VALUE)是字符串形式的表达式,比如 TO_DATE(' 2023-01-01 00:00:00', ...),空格、单引号、NLS 设置都可能导致你误判分区归属。不要靠肉眼猜,用以下方式安全提取:
SELECT partition_name,
EXTRACTVALUE(DBMS_XMLGEN.GETXMLTYPE(
'SELECT high_value FROM user_tab_partitions WHERE table_name=''SALES'' AND partition_name=''' || partition_name || ''''
), '/ROWSET/ROW/HIGH_VALUE') AS high_val
FROM user_tab_partitions
WHERE table_name = 'SALES';
真正危险的是边界日期处理:比如按月分区,p_202201 的 HIGH_VALUE 实际是 '2022-02-01',代表“小于该值”。想清理 2022 年全年,必须包含 p_202201 到 p_202212 共 12 个分区——漏一个,数据就残留了。











