ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 再说HWM(上)

再说HWM(上)

原创 Linux操作系统 作者:realkid4 时间:2011-09-14 22:19:02 0 删除 编辑

 

Oracle HWM(High Water Mark高水位线)是Oracle数据表存储结构的一个重要内容。简单的说,HWM就是存储分配的一个最高界限,标志着该数据存储对象使用空间的最高位置。

 

作为一个数据段segment对象,Oracle会根据系统的初始化设置和增大的空间请求,不断将各自独立的分区extent分配给segment用于存储。但是,分配的空间不一定立即使用满,HWM高水位线就是划分使用过used和未使用过unused界限的一条分界线。

 

本篇我们仔细分析HWM在存储中的作用,以及对Oracle数据库行为的影响。最后,我们分析一下解决HWM问题的方法。

 

1、HWM和存储分配

 

HWM高水位线是与Oracle数据段segment存储密切相关的一个基本概念。在Oracle中,存储逻辑结构是按照表空间tablespace、段对象segment、分区extent和数据块block进行分级别组织起来的。

 

一般我们的数据表就是对应一个段对象segment(分区表除外)。在我们创建一个数据表的时候,Oracle会创建出一个数据段对应。注意:在Oracle 11g中,提供了segment create deferred特性,不在本篇的讨论范畴。

 

我们使用Oracle 10gR2作为实验版本。

 

 

SQL> select * from v$version;

 

BANNER

----------------------------------------------------------------

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE     10.2.0.1.0       Production

 

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 – Production

 

SQL> create table t tablespace users as select * from dba_objects where 1=0;

Table created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

 

 

此时,数据表T中没有任何数据。

 

 

SQL> select segment_name, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS from dba_segments where segment_name='T' and wner='SYS';

 

SEGMENT_NA HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

---------- ----------- ------------ ---------- ---------- ----------

T                    4         5203      65536          8          1

 

SQL> select segment_name, EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS, RELATIVE_FNO from dba_extents where wner='SYS' and segment_name='T';

 

SEGMENT_NA  EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO

---------- ---------- ---------- ---------- ---------- ---------- ------------

T                   0          4       5201      65536          8            4

 

 

 

对数据表T,Oracle分配了一个分区作为初始分区。该extent编号(内部)为0,位于file_id=4, block_id=5201的位置上。但是从数据段的角度看,数据表的头块是从5203开始,有两个数据块作为描述信息单独使用。注意,extent是连续存储的数据块block,该extent包括8个数据块,也就是覆盖编号从5201~5208范围。

 

 

SQL> select table_name, NUM_ROWS, BLOCKS, EMPTY_BLOCKS,AVG_SPACE  from dba_tables where table_name='T' and wner='SYS';

 

TABLE_NAME   NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE

---------- ---------- ---------- ------------ ----------

T                   0          0            8          0

 

 

此时,如果我们向其中插入一些数据。

 

 

SQL> insert into t select * from dba_objects where object_id<10 order by object_id;

8 rows inserted

 

SQL> commit;

Commit complete

 

SQL> select dbms_rowid.rowid_relative_fno(t.rowid) fno, dbms_rowid.rowid_block_number(t.rowid) block_num, dbms_rowid.rowid_row_number(t.rowid) row_num, object_id from t;

 

       FNO  BLOCK_NUM    ROW_NUM  OBJECT_ID

---------- ---------- ---------- ----------

         4       5205          0          2

         4       5205          1          3

         4       5205          2          4

         4       5205          3          5

         4       5205          4          6

         4       5205          5          7

         4       5205          6          8

         4       5205          7          9

 

8 rows selected

 

 

从上面我们可以看到一些现象。我们已经将extent分配给了segment T,其中的8个数据块是已经属于T的范围。当我们插入8条数据的时候,发现所在的都是一个数据块(fno=4, block_num=5205)中。

 

 

SQL> analyze table t compute statistics;

 

Table analyzed

 

SQL> select table_name, NUM_ROWS, BLOCKS, EMPTY_BLOCKS,AVG_SPACE  from dba_tables where table_name='T' and wner='SYS';

 

TABLE_NAME   NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE

---------- ---------- ---------- ------------ ----------

T                   8          5            3       7947

 

 

归纳一下,我们看到的情况,分区extent的起始位置是5201,而数据段segment的头块是5203,第一条数据插入的位置是5205。剩余所谓的3个empty_block的编号是:5206~5208。总数据的5个block,实际上是从5204~5208。但是5204用于段头信息保存(如extent分配bitmap等)。

 

这个时候,虽然5206~5208从隶属上已经划分给T,但是处在unused没用过的状态。数据块5205,显然是已经使用过的。HWM就在5205高度,表示当前达到的数据表最大存储使用位置。

 

随着数据的增加,数据块5205不能容纳的时候,就会向segment管理要求一个新的空闲块使用,此时就会分配5204~5208范围。此时,HWM就会推进到新的一个数据块中。

 

 

SQL> select distinct(dbms_rowid.rowid_relative_fno(t.rowid) ||'-'|| dbms_rowid.rowid_block_number(t.rowid))  from t;

 

(DBMS_ROWID.ROWID_RELATIVE_FNO

--------------------------------------------------------------------------------

4-5205

4-5206

 

 

此时,我们的数据是分布在两个数据块上,使用了两个数据块。此时,区分unused和used分界的HWM就在5206块上。

 

此处我们得到结论,一味的插入数据,会将更多的空间分配和使用给数据段,从而不断的推高水位线HWM。

 

如果我们删除数据,Oracle是否会自动将水位线下降呢?

 

 

SQL> insert into t select * from dba_objects;

50721 rows inserted

 

SQL> commit;

Commit complete

 

SQL> analyze table t compute statistics;

Table analyzed

 

SQL> select table_name, NUM_ROWS, BLOCKS, EMPTY_BLOCKS,AVG_SPACE  from dba_tables where table_name='T' and wner='SYS';

 

TABLE_NAME   NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE

---------- ---------- ---------- ------------ ----------

T               50721        748           20       1234

 

SQL> delete t;

 

50721 rows deleted

 

SQL> analyze table t compute statistics;

 

Table analyzed

 

SQL> select table_name, NUM_ROWS, BLOCKS, EMPTY_BLOCKS,AVG_SPACE  from dba_tables where table_name='T' and wner='SYS';

 

TABLE_NAME   NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE

---------- ---------- ---------- ------------ ----------

T                   0        748           20       7932

 

SQL> select count(*), sum(bytes)/1024/1024 mb from dba_extents where segment_name='T' and wner='SYS';

 

  COUNT(*)         MB

---------- ----------

        21          6

 

 

这就意味着,当我们不断插入数据的时候,Oracle会不断分配空间extents和数据块给segment进行填充,同时不断的推高HWM到一个新的位置。

 

但是我们的删除delete操作,无论是有条件的删除,还是全部删除,都是不会将已经分配、已经使用过的空间回收reclaim的。空间不能回收的原因在与堆表的数据行是分散保存的,回收空间要保证该空间上没有任何数据,也就是要保证对数据行进行移动。这点对于delete操作是不可行的。

 

由于Oracle空间分配和存储上的特性,引起了在DML操作中,HWM一般都是只增加、不会轻易下降的现象。

 

 

2、推高HWM

 

下面说说堆表heap table的结构。堆表Heap Table是我们最常使用的一种数据表类型,它的特点就是存储随机,读取顺序。Heap Table的高水位线就相当一个数据框,限定了数据表存储的空间范围。

 

对Heap Table而言,当一般的insert操作进行时,Oracle首先会去寻找HWM下的空间有无空闲存在,如果有的话,就设法使用这些空间进行保存。这些空间是由于过去数据被删除,该物理位置就留出现空间可以使用。

 

如果在HWM下没有找到相应的位置,Oracle就会设法分配新的数据块使用,从而推高HWM。

 

在整个流程中,Oracle实际上在不断尝试寻找合适的存储。有三种方式,可以让Oracle插入数据时候会避开尝试在HWM下找空间的过程,直接推高水位线,获取较好的效率。

 

ü        顺序化的direct_load操作,使用hint /*+ append*/就可以在insert语句执行的时候,直接推高HWM;

ü        并行化parallel直接加载操作,对一个数据表设置并行度,采用多Slave Process处理操作;

ü        SQL Load进行加载时,参数direct设置为Y,表示直接加载;

 

上述三种操作,都会直接推高HWM,而且是绕开SGA的Buffer Cache进行操作。

 

本篇中,我们简单介绍了HWM的特性。下面我们介绍HWM会给日常Oracle操作带来什么影响,以及出现HWM问题后一些常见的处理方式。

 

 

 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/17203031/viewspace-707432/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: 再说HWM(下)
请登录后发表评论 登录
全部评论
求道~

注册时间:2010-11-30

  • 博文量
    545
  • 访问量
    8040075