2026年01月21日/ 浏览 6
表碎片主要是由于频繁的DML操作导致数据块中出现空闲空间,使得高水位线(HWM)下存在大量无数据块。数据库中的表碎片会降低查询效率,增加不必要的I/O操作。以下是收缩表碎片的常用方法,以 Oracle 数据库为例。
这是Oracle官方推荐的在线碎片整理方法,对业务影响较小。
启用行移动:这是执行收缩操作的前提。ALTER TABLE your_table_name ENABLE ROW MOVEMENT;执行收缩:根据你的需求选择不同的收缩选项。操作
说明
适用场景
ALTER TABLE your_table_name SHRINK SPACE COMPACT;
仅重组数据,不降低高水位线(HWM),不释放空间。对业务影响小。
业务繁忙时段进行初步整理。
ALTER TABLE your_table_name SHRINK SPACE;
重组数据并降低高水位线,释放空间。此过程会短暂锁表。
业务低峰期进行最终的空间回收。
ALTER TABLE your_table_name SHRINK SPACE CASCADE;
收缩表的同时,自动收缩该表上的所有索引。
需要同时整理表和索引碎片。
关闭行移动(可选):收缩完成后,可以选择关闭行移动。
ALTER TABLE your_table_name DISABLE ROW MOVEMENT;MOVE表是另一种整理碎片的方法,但它在操作期间会对表施加更强的锁,影响DML操作,并且会使所有索引失效。
ALTER TABLE your_table_name MOVE;操作完成后,必须重建索引:
ALTER INDEX your_index_name REBUILD;确认碎片程度:在操作前,先查询数据字典判断碎片化的严重程度。
SELECT table_name, ROUND((blocks * 8), 2) "高水位空间 k", ROUND((num_rows * avg_row_len / 1024), 2) "真实使用空间 k", ROUND((blocks * 8) - (num_rows * avg_row_len / 1024) - (blocks * 8 * 10 / 100), 2) "浪费空间 k" FROM user_tables WHERE table_name = YOUR_TABLE_NAME;如果“浪费空间”很大,则整理的必要性很高。
确认表空间管理方式:SHRINK命令要求表所在的表空间为自动段空间管理(ASSM)。
注意限制:SHRINK命令不适用于簇表、包含LONG类型的表、带有函数索引的表以及压缩表等。
通过对比整理前后表所占用的空间和碎片率来判断效果。
查看段空间使用情况:查询 DBA_SEGMENTS视图,关注 BYTES和 BLOCKS列。整理成功后,这些值应该有明显下降。
SELECT segment_name, bytes/1024/1024 as "SIZE_MB", blocks FROM dba_segments WHERE segment_name = YOUR_TABLE_NAME AND owner = TABLE_OWNER;计算表碎片率:通过 USER_TABLES或 DBA_TABLES中的统计信息计算,可以量化碎片程度。整理后,这个比率应该趋近于0。
SELECT table_name, ROUND((blocks * 8192 / 1024 / 1024), 2) AS "HWM_SIZE_MB", ROUND((num_rows * avg_row_len / 1024 / 1024), 2) AS "ACTUAL_DATA_SIZE_MB", ROUND((blocks * 8192 / 1024 / 1024) - (num_rows * avg_row_len / 1024 / 1024), 2) AS "FRAGMENTED_SPACE_MB", CASE WHEN blocks > 0 THEN ROUND((num_rows * avg_row_len) / (blocks * 8192), 4) * 100 ELSE 0 END AS "EFFECTIVENESS_PERCENTAGE" FROM dba_tables WHERE table_name = YOUR_TABLE_NAME AND owner = TABLE_OWNER;碎片空间(FRAGMENTED_SPACE_MB):理想情况下应大幅减少。
表使用效率(EFFECTIVENESS_PERCENTAGE):这个百分比越高,说明HWM以下的数据块填充越满,效果越好。
注意:在运行这些查询前,请先收集最新的表统计信息,以确保数据准确。
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => TABLE_OWNER, TABNAME => YOUR_TABLE_NAME);碎片整理的一个重要目标是减少全表扫描时需要读取的数据块数量,从而提升查询速度。
比较执行计划成本:对表进行简单的全表扫描查询,使用 EXPLAIN PLAN查看执行计划。整理后,全表扫描的 Cost(成本) 值应该有所下降。EXPLAIN PLAN FOR SELECT * FROM your_table_name; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);如果使用了 ALTER TABLE ... MOVE或 SHRINK SPACE CASCADE等方法,需要确保表和索引仍然处于有效状态。
检查索引状态:查询 DBA_INDEXES视图。SELECT index_name, status FROM dba_indexes WHERE table_name = YOUR_TABLE_NAME AND table_owner = TABLE_OWNER;如果状态不是 VALID,则需要重建索引。ALTER INDEX your_index_name REBUILD ONLINE;对于特别重要的表,可以使用Oracle提供的 DBMS_SPACE包进行更深入的空间分析,查看数据块内部的利用率。
DECLARE l_unformatted_blocks NUMBER; l_unformatted_bytes NUMBER; l_fs1_blocks NUMBER; l_fs1_bytes NUMBER; l_fs2_blocks NUMBER; l_fs2_bytes NUMBER; l_fs3_blocks NUMBER; l_fs3_bytes NUMBER; l_fs4_blocks NUMBER; l_fs4_bytes NUMBER; l_full_blocks NUMBER; l_full_bytes NUMBER; BEGIN DBMS_SPACE.SPACE_USAGE( segment_owner => TABLE_OWNER, segment_name => YOUR_TABLE_NAME, segment_type => TABLE, unformatted_blocks => l_unformatted_blocks, unformatted_bytes => l_unformatted_bytes, fs1_blocks => l_fs1_blocks, fs1_bytes => l_fs1_bytes, fs2_blocks => l_fs2_blocks, fs2_bytes => l_fs2_bytes, fs3_blocks => l_fs3_blocks, fs3_bytes => l_fs3_bytes, fs4_blocks => l_fs4_blocks, fs4_bytes => l_fs4_bytes, full_blocks => l_full_blocks, full_bytes => l_full_bytes ); DBMS_OUTPUT.PUT_LINE(Full Blocks (75-100% full): || l_full_blocks); DBMS_OUTPUT.PUT_LINE(FS4 Blocks (50-75% full): || l_fs4_blocks); -- ... 可以输出其他分段的数据 END; /整理成功后,full_blocks(利用率75%-100%的块)数量应增加,而 fs1_blocks(0-25%满)等利用率低的块应减少。