一、oracle 高水位线详解
一、什么是水线(High Water Mark)?
所有的oracle 段(segments,在此,为了理解方便,建议把segment 作为表的一个同义词) 都
有一个在段内容纳数据的上限,我们把这个上限称为"high water mark"或HWM。这个HWM
是一个标记,用来说明已经有多少没有使用的数据块分配给这个segment。HWM 通常增长的
幅度为一次5个数据块,原则上HWM 只会增大,不会缩小,即使将表中的数据全部删除,HWM
还是为原值,由于这个特点,使HWM 很象一个水库的历史最高水位,这也就是HWM 的原始含
义,当然不能说一个水库没水了,就说该水库的历史最高水位为0。但是如果我们在表上使
用了truncate 命令,则该表的HWM 会被重新置为0。
二、HWM 数据库的操作有如下影响:
a) 全表扫描通常要读出直到HWM 标记的所有的属于该表数据库块,即使该表中没有任何数
据。
b) 即使HWM 以下有空闲的数据库块,键入在插入数据时使用了append 关键字,则在插入时
使用HWM 以上的数据块,此时HWM 会自动增大。
三、如何知道一个表的HWM?
a) 首先对表进行分析:
1 ANALYZE TABLE <tablename> ESTIMATE/COMPUTE STATISTICS;
b)
说明:
BLOCKS 列代表该表中曾经使用过得数据库块的数目,即水线。
EMPTY_BLOCKS 代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。
让我们以一个有28672行的BIG_EMP1表为例进行说明:
1 1) SQL> SELECT segment_name, segment_type, blocks FROM dba_segments WHERE segment_name='BIG_EMP1'; 2 SEGMENT_NAME SEGMENT_TYPE BLOCKS 3 ----------------- -------------- --------- 4 BIG_EMP1 TABLE 1024 5 1 row selected. 6 7 2) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; 8 9 Statement processed. 10 11 3) SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='BIG_EMP1'; 12 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 13 ---------- -------- ------- ------------- 14 BIG_EMP1 28672 700 323 15 1 row selected. 16 --注意: 17 /*BLOCKS + EMPTY_BLOCKS (700+323=1023)比DBA_SEGMENTS.BLOCKS 少1个数据库块,这是因 18 为有一个数据库块被保留用作segment header。DBA_SEGMENTS.BLOCKS 表示分配给这个表 19 的所有的数据库块的数目。USER_TABLES.BLOCKS 表示已经使用过的数据库块的数目。*/ 20 4) SQL> SELECT COUNT (DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)|| DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used" FROM big_emp1; 21 Used 22 ---------- 23 700 24 1 row selected. 25 26 5) SQL> delete from big_emp1; 27 28 28672 rows processed. 29 30 6) SQL> commit; 31 32 Statement processed. 33 34 7) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; 35 36 Statement processed. 37 38 8) SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='BIG_EMP1'; 39 40 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 41 --------- -------- ------- ---------- 42 BIG_EMP1 0 700 323 43 1 row selected. 44 45 9) SQL> SELECT COUNT (DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)|| DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used" FROM big_emp1; 46 Used 47 ---------- 48 /* 49 0 ----这表名没有任何数据库块容纳数据,即表中无数据 */ 50 1 row selected. 51 10) SQL> TRUNCATE TABLE big_emp1; 52 Statement processed. 53 11) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; 54 Statement processed. 55 12) SQL> SELECT table_name,num_rows,blocks,empty_blocks 56 2> FROM user_tables 57 3> WHERE table_name='BIG_EMP1'; 58 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 59 ---------- -------- -------- ------------ 60 BIG_EMP1 0 0 511 61 1 row selected. 62 13) SQL> SELECT segment_name,segment_type,blocks 63 FROM dba_segments 64 WHERE segment_name='BIG_EMP1'; 65 SEGMENT_NAME SEGMENT_TYPE BLOCKS 66 ------------ ------------- ------ 67 BIG_EMP1 TABLE 512 68 1 row selected. 69 /* 70 注意: 71 TRUNCATE 命令回收了由delete 命令产生的空闲空间,注意该表分配的空间由原先的1024块 72 降为512块。 73 为了保留由delete 命令产生的空闲空间,可以使用TRUNCATE TABLE big_emp1 REUSE 74 STORAGE. 75 用此命令后,该表还会是原先的1024块。*/
四、Oracle 表段中的高水位线HWM
在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 的。
五、修正ORACLE 表的高水位线
在ORACLE 中,执行对表的删除操作不会降低该表的高水位线。而全表扫描将始终读取一个
段(extent)中所有低于高水位线标记的块。如果在执行删除操作后不降低高水位线标记,则
将导致查询语句的性能低下。下面的方法都可以降低高水位线标记。
1.执行表重建指令alter table table_name move;
(在线转移表空间ALTER TABLE 。。。MOVE TABLESPACE 。。。ALTER TABLE 。。。MOVE 后面
不跟参数也行,不跟参数表还是在原来的表空间,move 后记住重建索引。如果以后还要继
续向这个表增加数据,没有必要move,只是释放出来的空间,只能这个表用,其他的表或
者segment 无法使用该空间)
2.执行alter table table_name shrink space;
注意,此命令为Oracle 10g 新增功能,
再执行该指令之前必须允许行移动alter table table_name enable row movement;
实质上构造一个新表(在内部表现为一系列的DML 操作,即将副本插入新位置,删除原来位
置的记录)靠近末尾处(右端)数据块中的记录往开始处(左端)的空闲空间处移动(DML 操作),
不会引起DML 触发器
当所有可能的移动被完成,高水位线将会往左端移动(DDL 操作)
;新的高水位线右边的空闲空间被释放(DDL 操作);
实现前提条件
必须启用行记录转移(enable row movement)
仅仅适用于堆表,且位于自动段空间管理的表空间(堆表包括:标准表,分区表,物化视图容器,
物化视图日志表)