在Oracle的逻辑存储结构中(表空间-段-区-块),数据是存在数据段中的,通常一个表就是一个数据段,而段最终又由许多数据块组成。当数据存入数据块时,需要对块进行格式化,高水位线(High Water Mark, HWM)是段中的一个点,在这个点之上的所有数据块都是未格式化且未使用的。
文章目录
- 一、高水位线和低-高水位线的概念
- 二、高水位线的影响
- 三、降低表的高水位线
一、高水位线和低-高水位线的概念
在默认的自动段空间管理(ASSM)模式下,Oracle使用位图来管理段内的空间分配。HWM的从表开始创建开始,变化过程如下:
1.新建一张表(数据段)时,段内所有的数据块都是未格式化(格子代表数据块)且未使用的,此时的HWM位于段的开头:
2.当insert语句向表中插入数据时,Oracle会分配一部分数据块,并向右移动HWM。HWM以下的数据块代表已分配,但分配的块可能用不完,而且只有当数据真正写入某个块时(蓝色格子),才会对块进行格式化,因此引入低-高水位线(Low High Water Mark, LHWM)来表示所有已经格式化的块。
3.随着表内的数据不断更新和删除,数据段的状态可能变成这样:
- LHWM之下所有数据块都是已格式化的,可能包含数据,也可能不包含数据
- LHWM和HWM之前的数据块都是已分配,可能格式化,也可能未格式化
- HWM之上的数据块都是未分配且未格式化的
二、高水位线的影响
LHWM和HWM主要影响全表扫描的效率,当SQL查询需要进行全表扫描时,Oracle会进行如下操作:
- 获取LHWM的位置,读取LHWM之下的所有块,因为它们已格式化,代表使用过。
- 然后读取位于LHWM和HWM之间的已格式化块,避开未格式化的块。
所以全表扫描会扫描HWM下的所有已格式化的块。但从上面的图上可以看出,随着数据的更新,删除,HWM之下很多块可能已经没有数据了(碎片空间),但是依然会扫描该块。
一个极端的例子是使用delete删除表中所有记录时,HWM并不会下降,因此全表扫描的实际开销没有任何减少。这就是为什么使用delete删除一张大表后,你会发现即使表是空的或仅有很少数据,用select * from table;语句查询依然要花很长时间。
另外,当用直接路径插入(Direct-Path Insert)插入数据时(用APPEND提示或通过SQL*Loader直接路径),数据会直接从HWM之上开始写入,HWM下面的未使用的空间就浪费掉了。这个操作也会产生大量的碎片空间。
三、降低表的高水位线
当表经过长时间使用/直接路径插入/大量数据删除这些操作后,HWM之下很可能会有大量的碎片空间,在遇到全表扫描的操作时,性能低下,为了让数据更“紧凑”,需要降低表的HWM。
降低高水位线的方法有:
- 重建(rebuild),用expdp/impdb导出、导入来完成表的重建。
- 替换(replace),将表的数据复制到一张同结构中间表,drop源表,然后将中间表重命名为源表。
- 截断(truncate),清空表中数据时使用truncate代替delete。
- 移动(move),使用alter table tbl_name move;语句移动数据行,要重建索引。
- 收缩(shrink),使用alter table enable row movement; 和 alter table tbl_name shrink space语句收- 缩表,相比移动可以保持索引有效,但会产生大量undo和redo日志。