最近遇到一个需要降低高水位线的场景,首先梳理一下高水位线的知识。
如果我们把表想象成一个平面结构,或者想象成从左到右依次排开的一系列块。
高水位线(High-Water Mark,HWM)就是包含过数据的最右边的块,也可以想象为一个水库的历史最高水位。
HWM是表段的专用术语。
从上图可见,新创建的表HWM位于第一个块中,随着数据库不断插入,HWM会升高。
当我们删除掉表中部分或者全部数据的时候,可能就会有许多块不再包含数据,但是这些块仍然在高水位线下。直到重建、truncate或者收缩(shrink space)这个表(具体的降低高水位的方式,后面会单独说)。
注意:
Oracle在全表扫描时会扫描HWM之下的所有块,即使其中不包含任何数据。这直接影响了全表扫描的性能,特别是当HWM之下的大多数块都为空时。
举例来说,一个100万行数据的表,执行select count(*)操作,然后delete掉其中数据,再次select count(*),会发现执行时间一样长。这是因为Oracle忙于读取HWM之下的所有块,并查看其中是否包含数据。
这块比较难懂,我们要知道 low HWM只存在于自动段空间管理(ASSM)中。
使用CREATE TABLESPACE 语句创建一个本地管理的表空间(locally managed tablespace)时,可以使用SEGMENT SPACE MANAGEMENT 子句来设定段(segment)内的可用/已用空间如何管理。
[SEGMENT SPACE MANAGEMENT MANUAL|AUTO]
--查看我的虚拟机内表空间的段空间管理方式
SQL> select tablespace_name,SEGMENT_SPACE_MANAGEMENT from dba_tablespaces;
TABLESPACE_NAME SEGMEN
--------------------------- -------
SYSTEM MANUAL
SYSAUX AUTO
UNDOTBS1 MANUAL
TEMP MANUAL
USERS AUTO
TEST AUTO
下面是官方文档说明:
ASSM段中的每个数据块都处于以下状态之一:
直接说我的理解:low HWM的意义就是提高全表扫描效率,低于low HWM的块不需要判断是否格式化,直接读取,而low HWM 到 HWM之间的块,因为有的格式化,有的没有,所以需要先判断是否格式化过,再读取,这样效率就低。
注意:官方文档上额外说到,如果在 low HWM之下有空余空间的任何块,也会被插入。
所以,当全面扫描一个段时,必须知道被读取的块是否“安全”,或是否未格式化。
为了避免对表中的每一个块都进行这种“安全/不安全”检查,Oracle同时维护了一个低HWM和一个HWM。当Oracle全表扫描至HWM后,会对低HWM以下的所有块直接读取并加以处理。而对介于低HWM和HWM之间的块,则会更加小心,需要参考管理这些块所用的ASSM位图信息以便查看应该读取哪些块,以及哪些块应该被忽略。
在itpub上看到一个人举得例子比较好
MSSM就好比在VM创建虚拟机的时候,选择【立即分配所有磁盘】,要多大空间直接就给了。 ASSM就像是不勾选,创建完成虚拟机,df也是看到想要的大小,但是实际上只是个标识,没有实际分配,用到的时候再分。