oracle点知识——HWM(高水位线) 下

1、何时应该降低 HWM

table中包含两种空闲的block,在HWM之上的空闲block 和 在HWM之下的空闲block。

1、在HWM之上的空闲block : 运行analyze table后,在HWM之上的空心啊block会在user_tables 的 empty_blocks中 被统计,这些空闲的blocks实际上是从来没有存储过数据的,可以用以下命令来释放这些空间:

SQL>  alter table table_name  deallocate unused;


下面做一个实验来验证以下:

SQL> create table my_objects3 as select * from all_objects;

表已创建。            ——创建一个新表,一会用于测试

先分析一下:

SQL> exec show_space(p_segname=>'MY_OBJECTS3' ,p_owner=> 'SYS' ,p_type=>'TABLE');
Total Blocks............................768
Total Bytes.............................6291456
Unused Blocks...........................118
Unused Bytes............................966656
Last Used Ext FileId....................1
Last Used Ext BlockId...................57225
Last Used Block.........................10

高水位线在 768-118 + 1 = 651块 处。


查询在HWM之上的空闲blocks数量:
SQL> select empty_blocks from user_tables where table_name='MY_OBJECTS2';

EMPTY_BLOCKS
------------


哎哎。。我擦,没有出现结果,然后去oracle的参考文档,查到了下面的一些话:

EMPTY_BLOCKS* NUMBER   Number of empty (never used) data blocks in the table

Note:

Columns marked with an asterisk (*) are populated only if you collect statistics on the table with the ANALYZE statement or the DBMS_STATS package.(意思就是说先经过分析,才能查出数据来。)
那好吧,既如此,咱们就给分析一下吧。用如下语句分析:

SQL> analyze table my_objects3 compute statistics;
表已分析。

SQL> select empty_blocks from user_tables where table_name='MY_OBJECTS3';
EMPTY_BLOCKS
------------

   118

这下出来了。。。有118个块没有存储过数据。。。

继续用我们今天开篇介绍的语句alter table 。。。。deallocate unused 消除没有使用的数据块。

SQL> alter table my_objects3 deallocate unused;
表已更改。

SQL> analyze table my_objects3 compute statistics;
表已分析。

SQL> select empty_blocks from user_tables where table_name='MY_OBJECTS3';
EMPTY_BLOCKS
------------
           6

SQL> exec show_space(p_segname=>'MY_OBJECTS3' ,p_owner=> 'SYS' ,p_type=>'TABLE');
Total Blocks............................656         ——与之前的统计比,减少了112块。
Total Bytes.............................5373952
Unused Blocks...........................6          ——与之前统计比,减少了118-6=112块。
Unused Bytes............................49152
Last Used Ext FileId....................1
Last Used Ext BlockId...................57225
Last Used Block.........................10

PL/SQL 过程已成功完成。

高水位线在 656-6+1=651 处 ,此时,表的高水位线没有变化,其实我们完全可以理解,因为alter table 。。 deallocate unused ; 只是清除的HWM之上的块。这一点在我们开始就说明了。在此也得到了验证。


2、在HWM 之下的空闲block

当数据插入到一个block后,那么HWM就移动到这个block之上了。然后后续的操作又将这个block中的数据删除了,那么,这个block实际上是空闲的。但是这些block位于HWM之下,所以是不会出现在empty_blocks 列中的。那么这样的,在HWM之下的块过多会影响性能的,就像前面讨论过的 table full scan 中看到的那样。

下面测试:

SQL> delete from my_objects3 where rownum<15000;

已删除14999行。

SQL> exec show_space(p_segname=>'MY_OBJECTS3' ,p_owner=> 'SYS' ,p_type=>'TABLE');
Total Blocks............................656
Total Bytes.............................5373952
Unused Blocks...........................6
Unused Bytes............................49152
Last Used Ext FileId....................1
Last Used Ext BlockId...................57225
Last Used Block.........................10

PL/SQL 过程已成功完成。
 可以看到删除了之后没有任何变化。这是因为删除操作不会对HWM 进行移动。

3、在assm中HWM下的blocks使用情况

运用一个脚本:
http://blog.csdn.net/changyanmanman/article/details/8209377 (第二个过程)

执行效果:
SQL> exec show_space_assm('MY_OBJECTS3','SYS');
BEGIN show_space_assm('MY_OBJECTS3','SYS'); END;
*
第 1 行出现错误:
ORA-10614: Operation not allowed on this segment            ——在system表空间上不允许执行这个过程。
ORA-06512: at "SYS.DBMS_SPACE", line 159
ORA-06512: at "SYS.SHOW_SPACE_ASSM", line 28
ORA-06512: at line 1

查看报错原因,如此说来我们只能从user 表空间上重新创建一个表,然后来分析。

SQL> conn scott/liu123
已连接。

SQL> create table my as select * from all_objects ;
表已创建。


SQL> SET SERVEROUTPUT ON
SQL>  exec show_space_assm('MY','SCOTT');
free space 0-25% blocks:................0
free space 25-50% blocks:...............0
free space 50-75% blocks:...............0
free space 75-100% blocks:..............0
Full Blocks:............................545
Unformatted Blocks:.....................0

PL/SQL 过程已成功完成。
可以看到这些块,全是满的块。


SQL> delete from my where rownum < 15000;   ——删除一些块之后继续测试
已删除14999行。

SQL>  exec show_space_assm('MY','SCOTT');
free space 0-25% blocks:................0
free space 25-50% blocks:...............0
free space 50-75% blocks:...............0
free space 75-100% blocks:..............206
Full Blocks:............................339
Unformatted Blocks:.....................0
PL/SQL 过程已成功完成。
SQL>

这下一看就知道,一些块里的数据被删除了,这样一来不满的块也就多了。。。

闲着没事,又执行了一些show_space 空间统计的过程:

SQL> exec show_space(p_segname=>'MY' ,p_owner=> 'SCOTT' ,p_type=>'TABLE');
Total Blocks............................640
Total Bytes.............................5242880
Unused Blocks...........................77
Unused Bytes............................630784
Last Used Ext FileId....................7
Last Used Ext BlockId...................264
Last Used Block.........................51
PL/SQL 过程已成功完成。

简单算了一下,总共用的块数是640-77=563 ; 但是通过show_space_assm过程算出来的块是:206+339=545 。 这两个相差18个块。目前不知道这18个块是怎么回事,如果有懂的同学请各位留个言哈。。


2、如何降低HWM

8i以前的版本中,如果需要降低segment的HWM.  可以采用两种方法,分别是 exp/imp  和 CTAS 

(ctas 参照博客:http://blog.csdn.net/changyanmanman/article/details/8211253)这两种方法大家都很熟悉,不必多说,下面介绍3种降低HWM 的方法,顺便学习这三个命令。

1、move 命令

从8i开始,oracle提供了move命令。通常使用这个命令将一个table segment 从一个tablespace 移动到另一个tablespace。move实际上是在block之间物理的copy数据。

书上做了一个实验,经过alter table table_name move; 命令操作之后,表的blockid 会发生变化,也就是说会重新移动表的数据,重新拷贝 block 到新的块。很明显只要blockid变化了。。那rowid 就肯定的。。不是原来的了。。。

下面我们通过my 表删除行进行测试:

SQL> select table_name from user_tables;
TABLE_NAME
------------------------------
MY
SALGRADE
BONUS
EMP
DEPT


SQL> select count(*) from my;
  COUNT(*)
----------
     23954


SQL> set serveroutput on
SQL> exec show_space(p_segname=>'MY' ,p_owner=> 'SCOTT' ,p_type=>'TABLE');
Total Blocks............................640
Total Bytes.............................5242880
Unused Blocks...........................77
Unused Bytes............................630784
Last Used Ext FileId....................7
Last Used Ext BlockId...................264
Last Used Block.........................51
PL/SQL 过程已成功完成。

SQL> delete from my where rownum<1000;
已删除999行。

SQL> exec show_space(p_segname=>'MY' ,p_owner=> 'SCOTT' ,p_type=>'TABLE');
Total Blocks............................640
Total Bytes.............................5242880
Unused Blocks...........................77
Unused Bytes............................630784
Last Used Ext FileId....................7
Last Used Ext BlockId...................264
Last Used Block.........................51
PL/SQL 过程已成功完成。


SQL> alter table my move;
表已更改。

SQL> exec show_space(p_segname=>'MY' ,p_owner=> 'SCOTT' ,p_type=>'TABLE');
Total Blocks............................384
Total Bytes.............................3145728
Unused Blocks...........................46
Unused Bytes............................376832
Last Used Ext FileId....................7
Last Used Ext BlockId...................520
Last Used Block.........................82
PL/SQL 过程已成功完成。

这下可以看到HWM 下降了。

以下是alter table 中move子句的完整语法,这里介绍其中用的几点:

move [ONLINE]

   [segmetn_attributes_clause]

   [data_segment_compression]

  [index_org_table_clause]

  [{ LOB_storage | varray_col_properties}

     [ { LOB_storage_clause | varray_clo_properties } ] ...

 ]

 [parallel_clause]

可以使用move将一个table从当前的tablespace上移动到另一个tablespace上例如:

alter table  t  move tablespace tablespace_name;

还可以用move来改变table已有的block 的存储参数,例如:

alter table t move storage (initial 30k next 50k) ;

另外move操作也可以用来解决table上的行迁移问题。

使用move的一些注意事项

a、table上的index需要重建(rebuild): 这个自然不用说了,数据块拷贝,rowid 改变,索引自然失效。、

b、move时对table的锁定:对 my 表进行move操作的时候,查询v$locked_objects视图可以发现,my表上加了exclusive lock。

c、move时空间使用:当前的tablespace中需要1倍于table的空闲空间以供使用。 


2、DBMS_REDEFINITION

这个包是从9i开始引入的,用来做table的联机重组和重定义,可以通过这种方法在线的重组table、来移动table中的数据,降低HWM,修改table的存储参数,分区等。。

这个操作要求table上有一个主键,并要求预先创建一个带有要求修改该的存储参数的table,以便保存重新组织后的数据。保存重新组织的数据的table叫临时表。他只在重新组织期间被使用,在操作完成后可以被删除。

使用DBMS_REDEFINITION 包需要如下权限:

create any table;

alter any table;

drop any table;

lock any table;

select any table;

在dbms_redefinition上执行操作。使用dbms_redefinition重组table一般是这样几个步骤:

(1)使用dbms_redefinition. can_redef_table()验证所选择的table能够被重建。

(2)创建空的临时表,确保这个临时表定义了主键。

(3)使用dbms_redefinition.start_redef_table()进行table重组。

(4)在临时表上创建触发器、索引和约束,一般来说,这些对象与源表中的是一致的,但是名称必须不同。同时要确保所有外键约束不可用。在重组结束时,所有这些对象将替换定义在源表上的对象。

(5)使用dbms_redefinition.finish_redef_table() 完成重组过程。在这期间,源表将会lock较短的时间。

(6)删除临时表。


3、shrink 命令

如果表空间时自动段空间管理的(ASSM),就可以使用这个shrink 命令来缩小段,降低HWM,需要强调的是这个命令仅对assm 管理模式的段空间有效。

下面直接上测试过程吧:

SQL> select tablespace_name,block_size,extent_management, allocation_type,segment_space_management from dba_tablespaces where tablespace_name='ASSM';

TABLESPACE_NAME      BLOCK_ SIZE    EXTENT_MAN      LLOCATIO     SEGMEN
------------------------------       ----------                   ----------                 ---------             ------
  ASSM                                 8192                         LOCAL              SYSTEM          AUTO

SQL> create table my tablespace  assm as select * from all_objects;        ——创建测试表
表已创建。

SQL> select  count(*) from my;

  COUNT(*)
----------
     47231

在各个块中删除一些数据行,这样可以在各个数据块中出现空的地方,块就有很多不满的了。。。
SQL> delete from my where object_name like '%c%'  ;
已删除20950行。

SQL> delete from my where object_name like '%u%';
已删除4689行。

SQL> delete from my where object_name like '%a%' ;
已删除5644行。



SQL> set serveroutput on
SQL> exec show_space(p_segname=>'MY' ,p_owner=> 'SYS' ,p_type=>'TABLE');
Total Blocks............................768
Total Bytes.............................6291456
Unused Blocks...........................98
Unused Bytes............................802816
Last Used Ext FileId....................8
Last Used Ext BlockId...................776
Last Used Block.........................30
PL/SQL 过程已成功完成。

SQL> exec show_space_assm('MY','SYS');
free space 0-25% blocks:................0
free space 25-50% blocks:...............7
free space 50-75% blocks:...............12
free space 75-100% blocks:..............452
Full Blocks:............................179
Unformatted Blocks:.....................0
PL/SQL 过程已成功完成。

现在看来由于我们刚才的删除操作,有了很多的块不满了。。下面可以用shrink命令来重组了。。

在进行shrink之前,表必须支持 行移动,这个很重要的,可以用下面的命令实现:

SQL> alter table my enable row movement;
表已更改。

现在可以用以下命令来降低my表的HWM:

SQL> alter table my shrink space;
表已更改。

SQL> exec show_space(p_segname=>'MY' ,p_owner=> 'SYS' ,p_type=>'TABLE');
Total Blocks............................208
Total Bytes.............................1703936
Unused Blocks...........................1
Unused Bytes............................8192
Last Used Ext FileId....................8
Last Used Ext BlockId...................264
Last Used Block.........................79
PL/SQL 过程已成功完成。

SQL> exec show_space_assm('MY','SYS');
free space 0-25% blocks:................1
free space 25-50% blocks:...............0
free space 50-75% blocks:...............0
free space 75-100% blocks:..............1
Full Blocks:............................193
Unformatted Blocks:.....................0
PL/SQL 过程已成功完成。

可以看到HWM下降了。。。原来不满的数据块都基本变成满满的了。。。

最后一点:可以在shrink table的同时shrink这个table上的index:

alter table my shrink space cascade;

shrink命令内部的原理:

shrink命令内部的原理到底是什么样的?我们知道,在move命令操作的时候,所有的行的rowid都发生了变化,table所位于的block的区域也发生了变化,但是所有行物理存储的顺序是没有变化的,所以我们得到的结论是oracle以block为单位进行了block间的数据copy。

那么shrink后,可以发现部分行的rowid发生了变化,同时部分行的物理存储顺序也发生了变化,而table所位于的block区域却没有变化,这说明,shrink只移动了table其中的一部分行的数据来完成释放空间,而且这个过程是在table当前的使用的block中完成的。

shrink的时候oracle移动数据是以行为单位的。oracle从当前table的存储的最后一行数据开始移动,从当前table最先使用的block开始搜索空间,也就是最后一行会尽量往表块的最前面的空闲处插入。接着倒数第二行继续向前插入。。。一直重复这个过程。


shrink命令注意的问题:

a、shrink后index是否需要rebuild:在执行完成shrink收缩操作之后,通过查询语句:

select index_name,status from user_indexes where  index_name = '被收缩表生的index_name';

可以发现,index 的状态位 valid , 估计shrink 在移动行数据时,也一起维护了index上相应的数据rowid信息。可以认为,这是对move操作后需要 rebuild index的改进。但是如果一个table上的index数量较多,因为维护index的成本也是较高的,所以shrink过程中用来维护index的成本也会比较高。

b、shrink时对table的锁定: 在对table shrink时,会对table进行怎样的锁定呢?当对表my 进行shrink操作时,查询v$locked_objects 视图可以发现,表 my 上加了row-X(SX)的lock:

SQL > select  object_id , session_id, oracle_username,locked_mode from v$locked_objects;

OBJECT_ID       SESSION_ID     ORACLE_USERNAME        LOCKED_MODE

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

55422                     153                             DLINGER                                     3

SQL > select object_id from user_object where object_name = 'MY_OBJECTS';

OBJECT_ID

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

 55422

可以看出,当table进行shrink时,对table是可以进行DML操作的。


3、shrink对空间的要求:shrink不会像move一样,它不需要额外的空闲空间。


3、其他可以移动HWM 的操作

1、insert append

但是用 /* +insert append */ into 向一个table中插入数据时,oracle不会在HWM以下寻找空间,而是直接移动HWM, 从 EMPTY_BLOCKS 中获得要使用block空间,来满足这一操作对blocks的需要。

实验测试表中,我们建立了all_objects 的映像表,然后删除掉里面的全部数据, 再向表中 insert into (注意这个顺序) 1000条数据,重新分析表,发现HWM没有移动,还是在建表时的位置。

继续delete所有数据,重新用insert /*+append*/ into 语句插入数据,执行show_space过程分析,发现HWM向后移动了。而不会在前面空的块中插入数据。

下面我们比较一下insert into  和 insert /*+append* / into 的效率问题:

经过建空表,插入测试发现 insert into 会比 insert /*+ append*/ into 慢很多,这是为什么呢?

最后提一下,在使用 insert /*+ append*/ into  时,oracle会生成表级独占锁(对表加上 exclusive 模式的TM 锁),可以阻断其他会话的DML操作。

你可能感兴趣的:(oracle基础知识)