3.1.1 HWM (High Water Mark)
3.1.1.1 定义
To manage space, Oracle Database tracks the state of blocks in the segment. The high water mark (HWM) is the point in a segment beyond which data blocks are unformatted and have never been used.
- Above the HWM
These blocks are unformatted and have never been used.
- Below the HWM
- Allocated, but currently unformatted and unused
- Formatted and contain data
- Formatted and empty because the data was deleted
> ———-
The low high water mark (low HWM) marks the point below which all blocks are known to be formatted because they either contain data or formerly contained data.
the database chooses a block between the HWM and low HWM and writes to it. The database could have just as easily chosen any other block between the HWM and low HWM, or any block below the low HWM that had available space.
3.1.1.2 理解
在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,高水位线就会上涨,但是这里也有一个特性,就是如果你采用delete语句删除数据的话,数据虽然被删除了,但是高水位线却没有降低,还是你刚才删除数据以前那么高的水位。也就是说,这条高水位线在日常的增删操作中只会上涨,不会下跌。
下面我们来谈一下Oracle中Select语句的特性。Select语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。现在来想象一下,如果刚才是一张刚刚建立的空表,你进行了一次Select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。而如果这个时候你首先插入了一千万条数据,然后再用delete语句删除这一千万条数据。由于插入了一千万条数据,所以这个时候的高水位线就在一千万条数据这里。后来删除这一千万条数据的时候,由于delete语句不影响高水位线,所以高水位线依然在一千万条数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,所以需要把一千万条数据的存储空间都要扫描一次,也就是说这次扫描所需要的时间和扫描一千万条数据所需要的时间是一样多的。所以有时候有人总是经常说,怎么我的表中没有几条数据,但是还是这么慢呢,这个时候其实奥秘就是这里的高水位线了。
那有没有办法让高水位线下降呢,其实有一种比较简单的方法,那就是采用TRUNCATE语句进行删除数据。采用TRUNCATE语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM给清空恢复为0。所以如果需要把表清空,在有可能利用TRUNCATE语句来删除数据的时候就利用TRUNCATE语句来删除表,特别是那种数据量有可能很大的临时存储表。
在手动段空间管理(Manual Segment Space Management)中,段中只有一个HWM,但是在Oracle9iRelease1才添加的自动段空间管理(Automatic Segment Space Management)中,又有了一个低HWM的概念出来。为什么有了HWM还又有一个低HWM呢,这个是因为自动段空间管理的特性造成的。在手段段空间管理中,当数据插入以后,如果是插入到新的数据块中,数据块就会被自动格式化等待数据访问。而在自动段空间管理中,数据插入到新的数据块以后,数据块并没有被格式化,而是在第一次在第一次访问这个数据块的时候才格式化这个块。所以我们又需要一条水位线,用来标示已经被格式化的块。这条水位线就叫做低HWM。一般来说,低HWM肯定是低于等于HWM的。
3.1.1.3 影响
- 全表扫描通常要读出直到HWM标记的所有的属于该表数据库块,即使该表中没有任何数据。
- 即使HWM以下有空闲的数据库块,键入在插入数据时使用了append关键字,则在插入时使用HWM以上的数据块,此时HWM会自动增大。
3.1.1.4 实践
####################Truncate 降低HWM###########################
#分析表emp3
SQL> analyze table emp3 estimate statistics;
Table analyzed.
#查看高水位线为blocks=5
#BLOCKS 列代表该表中曾经使用过得数据库块的数目,即水线,
#USER_TABLES.BLOCKS表示已经使用过的数据库块的数目。
#EMPTY_BLOCKS 代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 19
#查看该段分配的块大小,blocks=8
#DBA_SEGMENTS.BLOCKS表示分配给这个表的所有的数据库块的数目
SQL> select segment_name, segment_type, segment_subtype, blocks
from dba_segments
where segment_name = ‘EMP3‘;
SEGMENT_NAME SEGMENT_TYPE SEGMENT_SU BLOCKS
--------------- ------------------ ---------- ----------
EMP3 TABLE ASSM 8
SQL> select count(*) from emp3;
COUNT(*)
----------
19
SQL> delete from emp3;
19 rows deleted.
SQL> commit;
Commit complete.
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 19
SQL> delete from emp3;
19 rows deleted.
SQL> commit;
Commit complete.
#delete 数据后无法把HWM降低
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 19
SQL> truncate table emp3;
Table truncated.
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 19
SQL> analyze table emp3 estimate statistics;
Table analyzed.
#使用Truncate表可以降低HWM
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
0 8 0
####################Shrink space 降低HWM###########################
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 19
SQL> delete from emp3 where dep_id = 2;
11 rows deleted.
SQL> commit;
Commit complete.
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 19
SQL> alter table emp3 shrink space;
alter table emp3 shrink space
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled
SQL> alter table emp3 enable row movement;
Table altered.
SQL> alter table emp3 shrink space;
Table altered.
SQL> analyze table emp3 estimate statistics;
Table analyzed.
SQL> select blocks, empty_blocks, num_rows from user_tables where table_name = ‘EMP3‘;
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
1 7 8