说到HWM,我们首先要简要的谈谈ORACLE的逻辑存储管理。我们知道,ORACLE在逻辑存储上分4个粒度: 表空间,段,区和块。
- 块(Oracle数据块)
块是Oracle粒度最小的存储单位,不同于操作系统磁盘块,现在标准的Oracle块大小是8K,ORACLE每一次I/O操作也是按块来操作的,也就是说当ORACLE从数据文件读数据时,是读取多少个块,而不是多少行。
- 区
由一系列相邻的块而组成,这也是ORACLE空间分配的基本单位,举个例子来说,当我们创建一个表PM_USER时,首先ORACLE会分配一区的空间给这个表,随着不断的INSERT数据到PM_USER,原来的这个区容不下插入的数据时,ORACLE是以区为单位进行扩展的,也就是说再分配多少个区给PM_USER,而不是多少个块。 一张表由若干区组成,这些区可以是不相邻的。
- 段
是由一系列的区所组成,一般来说,当创建一个对象时(表,索引),就会分配一个段给这个对象。所以从某种意义上来说,段就是某种特定的数据。如CREATE TABLE PM_USER
,这个段就是数据段,而CREATE INDEX ON PM_USER(NAME)
,ORACLE同样会分配一个段给这个索引,但这是一个索引段了。查询段的信息可以通过数据字典: SELECT * FROM USER_SEGMENTS
来获得, 通俗的讲,一张表对应一个段。
- 表空间
包含段,区及块。表空间的数据物理上储存在其所在的数据文件中,一个数据库至少要有一个表空间(SYSTEM)。一个表空间可能会保存在多个数据文件中。
HWM
在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。
ORACLE用HWM来界定一个段中使用过的块和未使用的块。
在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,HWM就会上涨,但是这里也有一个特性,就是采用delete
语句删除数据的话,数据虽然被删除了,但是HWM却没有降低,还是删除数据以前那么高的水位。
如果该表所在的表空间还有空闲,则新insert
的记录不会覆盖之前delete
的记录,而是会在新的位置插入,从而提升HWM。也就是说,HWM在日常的增删操作中只会上涨,不会下跌。
Oracle中Select
语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。
这样,频繁insert
和delete
的临时表,由于水线的提升,查询逐渐变慢就不奇怪了。
重置HWM
在ORACLE中,执行对表的delete
操作不会降低该表的高水位线。而全表扫描将始终读取一个段中所有低于HWM的块。如果在执行删除操作后不降低高水位线标记,则将导致查询语句的性能低下。
那有没有办法让高水位线下降呢,比较简单的方法是采用TRUNCATE
语句进行删除数据。采用TRUNCATE
语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM给清空恢复为0。所以如果需要把表清空,在有可能利用TRUNCATE
语句来删除数据的时候就利用TRUNCATE
语句来删除表,特别是那种数据量有可能很大的临时存储表。
下面的方法都可以降低高水位线标记。
几种重置HWM的方法
- MOVE表
MOVE表要求表空间剩余2倍当前表大小,且MOVE后需要重建索引。
- SHRINK表
注意,此命令为Oracle 10g新增功能,执行该指令之前必须允许行移动alter table table_name enable row movement;
复制要保留的数据到临时表t,drop原表,然后rename临时表t为原表
alter table table_name deallocate unused
truncate
表