时间: 2020-11-26|55次围观|0 条评论

一、声明:

     本人写的一些文章,其中有些是属于个人原创,有些属于转载+个人改编。就如本文属于转载+个人改编。

二、什么是水线(High Water Mark)?

     所有的Oracle段(segments,在此,为了理解方便,建议把segments作为表的一个同义词)都有一个在段内容纳数据的上限,我们把这个上限称为"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)、首先对表进行分析:

analyze table <tablename> extimate/compute statistics;
b)、查询HWM

select blocks,empty_blocks,num_rows from user_tables where table_name=<tablename>;

说明:

blocks列:代表该表中曾经使用过的数据库块的数目,即水线。

empty_blocks:代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。

下面将以示例进行说明:

 ----创建两张一样的表jack,echo------------
1
SQL> create table jack as select * from dba_objects; 2 3 Table created. 4 5 SQL> create table echo as select * from jack; 6 7 Table created. 8 ----查看一下分配给两张包的数据块---------------------
9
SQL> select segment_name,segment_type,blocks from dba_segments where segment_name in ('JACK','ECHO'); 10 11 SEGMENT_NAME SEGMENT_TYPE BLOCKS 12 --------------- ------------------ ---------- 13 ECHO TABLE 1152 14 JACK TABLE 1152 15 ----对两张表进行分析一下-------------------
16
SQL> analyze table jack compute statistics; 17 18 Table analyzed. 19 20 SQL> analyze table echo compute statistics; 21 22 Table analyzed. 23 ----查询表中数据块的内容----------------
24
SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name in ('JACK','ECHO'); 25 26 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 27 --------------------- ---------- ---------- ------------ 28 ECHO 72086 1126 26 29 JACK 72086 1053 99 30 ------------------------------------注意:
如果出现BLOCKS+EMPTY_BLOCKS(1126+26=1152)比DBA_SEGMENTS.BLOCKS少1个数据块,这是因为有一个数据库块被保留用作segment header。
DBA_SEGMENTS.BLOCKS表示分配给这个表的所有的数据库块的数目。USER_TABLES.BLOCKS表示已经使用过的数据库块的数目。
31 SQL> select count (distinct dbms_rowid.rowid_block_number(rowid)||dbms_rowid.rowid_relative_fno(rowid)) "Used" from jack; 32 33 Used 34 ---------- 35 1027 36 37 SQL> select count (distinct dbms_rowid.rowid_block_number(rowid)||dbms_rowid.rowid_relative_fno(rowid)) "Used" from echo; 38 39 Used 40 ---------- 41 1023 42 ----删除jack表中的内容---------------------
43
SQL> delete from jack; 44 45 72086 rows deleted. 46 47 SQL> commit; 48 49 Commit complete. 50 51 SQL> analyze table jack compute statistics; 52 53 Table analyzed. 54 55 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name in ('JACK','ECHO'); 56 57 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 58 ---------------------- ---------- ---------- ------------ 59 ECHO 72086 1126 26 60 JACK 0 1053 99 61 62 SQL> select count (distinct dbms_rowid.rowid_block_number(rowid)||dbms_rowid.rowid_relative_fno(rowid)) "Used" from jack; 63 64 Used 65 ---------- 66 0 ----该表没有任何数据库块容纳数据,即表中无数据 67 68 SQL> truncate table echo; 69 70 Table truncated. 71 72 SQL> analyze table echo compute statistics; 73 74 Table analyzed. 75 76 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name in ('JACK','ECHO'); 77 78 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 79 --------------------- ---------- ---------- ------------ 80 ECHO 0 0 8 81 JACK 0 1053 99 82 83 SQL> select segment_name,segment_type,blocks from dba_segments where segment_name in ('JACK','ECHO'); 84 85 SEGMENT_NAME SEGMENT_TYPE BLOCKS 86 --------------- ------------------ ---------- 87 ECHO TABLE 8 88 JACK TABLE 1152

  注意:TRUNCATE命令会回收空间,刚才echo表是1152块,现在变成了8块,为了保留空间,可以使用truncate table echo reuse storage.

 五、Oracle表段中的高水位线HWM

     在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条叫做水位线,在Oracle中,这个条线被称为高水位线(High-water 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,但是在Oracle9iR1才添加的自动段空间管理(Automatic Segment Space Managment)中,又有一个低HWM的概念出来。为什么有了HWM还又有一个低HWM呢,这个是因为自动段空间管理的特性造成的。在手动段空间管理中,当数据插入以后,如果是插入到新的数据块中,数据块就会被自动格式化等待数据访问。而在自动段空间管理中,数据插入到新的数据块以后,数据块并没有被格式化,而是在第一次访问这个数据块的时候才格式化这个块。所以我们又需要一条水位线,用来标识已经被格式化的块。这条水位线就叫做低HWM。一般来说,低HWM肯定低于等于HWM的。

六、修正Oracle表的高水位线

在Oracle中,执行对表的删除操作不会降低该表的高水位线。而全表扫描将始终读取一个段(extent)中所有低于高水位线标记的块。如果在执行删除操作后不降低高水位线标记,则将导致查询语句的性能降低。下面的方法就是可以降低高水位线标记。

1、执行表重建指令 alter table table_name move;

(在线转移表空间ALTER TABLE...MOVE TABLESPACE,在MOVE后面不跟参数也行,不跟参数表还是在原来的表空间,move后记住重建索引。如果以后还要继续向这个表增加数据,没有必要move,只是释放出来的空间,只能这个表用,其他的表或者segment无法使用该空间)。

2、执行alter table table_name shrink space;

注意:此命令为Oracle 10g新增加功能,再执行该指令之前必须允许行移动alter table table_name enbale row movement;

3、复制要保留的数据到临时表,drop原表,然后rename临时表为原表;

4、emp/imp

5、alter table table_name deallocate unused;

6、truncate

转载于:https://www.cnblogs.com/Richardzhu/articles/2847584.html

原文链接:https://blog.csdn.net/weixin_30342827/article/details/95097761

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自起风了,原文地址《Oracle之高水位线
   

还没有人抢沙发呢~