在Oracle数据库中,表碎片(Table Fragmentation)通常是由于频繁的DELETE、UPDATE操作导致高水位线(HWM, High Water Mark)居高不下,使得数据库在全表扫描时读取了大量包含已删除数据的空块,从而降低查询性能并浪费存储空间。
1 案例:
一次ogg数据库表同步,索引选择性很好,统计表统计信息也不管用,无法进行执行计划绑定,很纳闷,发现表delete很频繁,于是想重新对表进行碎片整理。

对表进行重建后,正常使用索引。
以下是处理Oracle表碎片的主要方式、适用场景及操作步骤:
1. 核心处理方法对比
| 方法 | 命令示例 | 是否在线 | 是否需要行移动 | 空间回收效果 | 适用场景 |
|---|---|---|---|---|---|
| Shrink Space | ALTER TABLE ... SHRINK SPACE |
是 (Online) | 必须启用 (ROW MOVEMENT) |
高 (降低HWM,释放空间给表空间) | 大多数堆表,希望在线整理并释放空间 |
| Move Table | ALTER TABLE ... MOVE |
否 (Offline) | 必须启用 (ROW MOVEMENT) |
高 (重建表,降低HWM) | 维护窗口充足,或无法使用Shrink的旧版本/特殊情况 |
| 在线重定义 | DBMS_REDEFINITION |
是 (Online) | 不需要 (内部处理) | 高 (重建表) | 业务不能中断,且表结构复杂或有依赖对象较多时 |
| 导出导入 | expdp/impdp |
否 (Offline) | 不需要 | 高 | 跨平台迁移或极度碎片化需彻底重建时 |
| 索引重建 | ALTER INDEX ... REBUILD |
可选 (ONLINE) |
N/A | N/A (仅针对索引) | 配合表整理,必须单独处理索引碎片 |
2. 推荐方案:ALTER TABLE ... SHRINK SPACE (最常用)
这是Oracle 10g引入的最便捷方式,可以在线压缩数据段,调整高水位线,并释放多余空间回表空间。
前置条件
- 表所在的表空间必须是 本地管理 (Locally Managed) 且 自动段空间管理 (ASSM)。
- 必须启用行移动功能:因为压缩过程中行的物理位置(RowID)会发生改变。
操作步骤
-- 1. 检查并启用行移动 (Row Movement)
ALTER TABLE your_table_name ENABLE ROW MOVEMENT;
-- 2. 执行收缩 (分两步走更稳妥,也可一步到位)
-- 2.1 紧凑数据 (Compact),只整理碎片,不降低高水位线,对业务影响最小
ALTER TABLE your_table_name SHRINK SPACE COMPACT;
-- 2.2 降低高水位线 (Cascade),释放空间给表空间,并级联处理索引
-- 注意:这一步会短暂持有锁,建议在业务低峰期执行
ALTER TABLE your_table_name SHRINK SPACE CASCADE;
-- 3. (可选) 如果之前为了安全开启了行移动,且业务逻辑强依赖RowID不变,可考虑关闭(通常建议保持开启)
-- ALTER TABLE your_table_name DISABLE ROW MOVEMENT;
COMPACT: 仅整理块内碎片,不调整HWM,不释放空间,耗时短,几乎不锁表。CASCADE: 同时整理表及其所有相关索引的碎片。
3. 备选方案:ALTER TABLE ... MOVE
如果表不支持SHRINK(例如非ASSM表空间),或者需要更改表的存储参数(如表空间、PCTFREE等),可以使用MOVE。
特点
- 缺点 :执行期间表不可用(锁表),所有索引会变为
UNUSABLE状态,必须重建。 - 优点:彻底重组数据,适用于任何表空间类型。
操作步骤
-- 1. 启用行移动
ALTER TABLE your_table_name ENABLE ROW MOVEMENT;
-- 2. 执行移动 (可指定新表空间或存储参数)
ALTER TABLE your_table_name MOVE;
-- 或者: ALTER TABLE your_table_name MOVE TABLESPACE new_tablespace;
-- 3. 重建索引 (因为MOVE后索引全部失效)
-- 手动重建
ALTER INDEX index_name REBUILD ONLINE;
-- 或者批量重建失效索引
BEGIN
FOR rec IN (SELECT index_name FROM user_indexes WHERE status = 'UNUSABLE') LOOP
EXECUTE IMMEDIATE 'ALTER INDEX ' || rec.index_name || ' REBUILD ONLINE';
END LOOP;
END;
/
4. 高级方案:在线重定义 (DBMS_REDEFINITION)
适用于对可用性要求极高(几乎零停机)、表上有复杂依赖(如触发器、约束、权限)的场景。它通过在后台创建新表、同步数据、切换指针的方式完成。
- 流程复杂 :需要调用
DBMS_REDEFINITION.START_REDEF_TABLE,SYNC_INTERIM_TABLE,FINISH_REDEF_TABLE等包。 - 优势:业务感知度最低,无需手动处理索引和约束(会自动迁移)。
5. 如何判断是否需要整理?
在执行操作前,建议先评估碎片程度。以下SQL可查询表的"浪费空间":
SELECT
table_name,
ROUND((blocks * 8 / 1024), 2) AS "高水位线大小 (MB)", -- 假设块大小为8KB
ROUND((num_rows * avg_row_len / 1024 / 1024), 2) AS "实际数据大小 (MB)",
ROUND(((blocks * 8) - (num_rows * avg_row_len / 1024)) / 1024, 2) AS "预估浪费空间 (MB)"
FROM user_tables
WHERE table_name = 'YOUR_TABLE_NAME'
AND (blocks * 8) > (num_rows * avg_row_len / 1024) * 1.2; -- 浪费超过20%视为有碎片
注:需确保统计信息是最新的,否则 num_rows 和 avg_row_len 可能不准。可先执行 EXEC DBMS_STATS.GATHER_TABLE_STATS('USER', 'TABLE_NAME');
也可以使用Oracle自带的 Segment Advisor 进行诊断:
-- 创建任务
DECLARE
tname VARCHAR2(100);
BEGIN
DBMS_ADVISOR.CREATE_TASK(DBMS_ADVISOR.SQLACCESS_ADVISOR, tname);
-- 具体参数设置较复杂,通常通过Enterprise Manager (OEM) 图形界面操作更方便
END;
/
6. 重要注意事项
- RowID 变化 :
SHRINK和MOVE都会改变行的ROWID。如果有应用程序硬编码了ROWID作为主键或引用,这些程序将失效。 - 索引失效 :
SHRINK SPACE CASCADE会自动维护索引。SHRINK SPACE(不带cascade) 不会更新索引,可能导致索引效率暂时下降,需后续重建。MOVE会导致所有索引失效,必须重建。
- Undo/Redo 压力:碎片整理本质是大量数据的更新和移动,会产生大量的 Undo 和 Redo 日志,务必确保归档空间和Undo表空间充足。
- 分区表 :如果是分区表,建议按分区进行整理(
ALTER TABLE ... MODIFY PARTITION ... SHRINK SPACE),避免一次性锁住整张大表。 - 外键约束 :如果父表进行
MOVE或SHRINK,子表的外键约束可能会带来额外的锁竞争,需谨慎评估。
总结建议
- 首选 :
ALTER TABLE ... SHRINK SPACE CASCADE(前提是ASSM表空间且允许Row Movement)。 - 大表/分区表:按分区逐个执行 Shrink,或在业务低峰期执行。
- 非ASSM环境 :使用
MOVE+REBUILD INDEX。 - 极致可用性 :使用
DBMS_REDEFINITION。