(一)高水位标记(High Water Mark,HWM)的概念
所谓高水位标记,是指一个已经分配的段中,已经使用的空间与未使用的空间的分界线。在表的使用过程中,随着数据的不断增多(insert),HWM不断向数据段未使用部分方向移动,而在删除数据(delete)的过程中,HWM并不会向反方向移动,即使删除全部数据,HWM依然不会改变。但是如果使用了truncate命令,则表的HWM会被重置为0。
图1.segment
(二)高水位标记的影响
全表扫描要读出直到HWM标记的所有的属于该表的数据块(used space),即使该表中没有任何数据; 即使HWM下有空闲的数据块,如果在插入数据时使用了append参数,则在插入数据时使用HWM以上的数据块,HWM会自动增大。
(三)如何知道一个表的HWM
1.首先对表进行分析
sql > ANALYZE table table_name ESTIMATE/COmpuTE STATISTICS;
2.查看水线
SELECT blocks,--该表曾经使用过的数据块的数目,即水线 empty_blocks,代表分配给该表,但是在水位线以上的数据块,即从来没有使用过的数据块 num_rowsFROM user_tablesWHERE table_name = ‘table_name’;
*注:在Oracle 11g中,收集数据库对象信息的最好方法,不再是使用带ESTIMATE或COmpuTE的ANALYSE语句,而是使用最新的DBMS_STATS包。但是,如果要收集数据库对象存储格式的有效性以及收集表与簇中的行迁移、行链接情况,还得使用ANALYSE。
(四)Oracle表段中的高水位线
每个Oracle数据块在ASSM段中都属于下面的一种状态:
高水位线以上这些块未被格式化且从来没有被使用过。
高水位线以下(3类)--已经分配,但是未格式化和未使用;
--格式化,且含有数据;
--格式化,不含有数据,因为数据被删除了。
(1)在创建表的时候,HWM位于segment左边的起始处,因为没有数据插入,segment中全部的block未被格式化和从未被使用。
(2)假设一个事务将行数据插入到segmnet中,数据库必须分配一组数据块去保存行信息,被分配的数据块全在HWM之下,数据库格式化一个位图块来保存元数据,但是没有指定是哪一个数据块。
在HWM以下的数据块是被分配的,在HWM以上的数据块从未被分配和格式化。当insert时,数据可以写到有可用空间的任何块中。low HWM以下的部分,所有的块都被格式化,因为它们要么含有数据,要么以前包含数据。
(3)当insert时,数据库选择在HWM和low HWM之间的任意一个块进行写入,或者是HWM以下的一个有空闲空间的块进行写入。下图中,在Low HWM与HWM之间已写满块的两侧的数据块还未格式化。
(4)low HWM对于全表扫描是非常重要的。因为HWM以下的数据块只有在要使用时才格式化,有一些块还未格式化。基于这个原因,数据库会去bitmap块查询low HWM的位置,然后会去读low HWM以下的全部数据块,因为数据库已经知道这些块全部被格式化了,对于在low HWM和HWM之间的数据块,数据库会挑选那些已经格式化了的数据块进行读 *** 作。
(5)假设一个新的事务进行插入 *** 作,但是bitmap指示目前在HWM以下已经没有足够的空间了,数据库会向右移动该segment的HWM,分配一组新的未格式化的数据块。
(五)降低HWM
降低HWM可以使用rebuild、truncate、shrink、move等 *** 作。
(5.1)SHRINK
shrink技术是一种段收缩技术,可将表与索引高水位以下的碎片进行有效压缩,并将高水位进行回退。
使用方法如下:
step1. 启用行移动
> ALTER table table_name ENABLE ROW MOVEMENT;step2. 压缩数据及下调HWM
table table_name SHRINK SPACE CASCADE; 压缩表及相关数据段并下调HWM或
SPACE COMPACT; 只压缩数据不下调HWMsql SPACE; 下调HWM即该技术可以一次性压缩数据及下调HWM,也可以分两个阶段进行,第一阶段:在业务高峰,只压缩数据不下调HWM,第二阶段:在业务空闲时,下调HWM。
(5.2)MOVE tablespace
语法为:
table table_name MOVE tableSPACE tablepsace_name;需要注意:
--MOVE后不跟参数也行,不跟参数还是原来的表空间;
--MOVE后需要重建索引;
--如果以后还要网表里插入数据,没必要MOVE。MOVE释放出来的空间,只能这个表使用,其它的表或者segment无法使用。
(5.3)CTAS技术
即重建表技术。
CREATE table new_table_name ASSELECT * FROM old_table_name; 将表的数据写入到一张新的表里DROP table old_table_name; 删除旧表> REname table new_table_name TO old_table_name 将新表名更改为旧表名(5.4)EXP/IMP或EXPDP/IMPDP技术
与CTAS技术相当。
(5.5)DEALLOCATE技术
利用DEALLOCATE技术可以回收HWM以上从未使用过的数据块。语法如下
table table_name DEALLOCATE UNUSED [KEEP integer]; --回收表段HWM以上的空间sql INDEX index_name ]; --回收索引段HWM以上的空间
(六)MOVE与SHRINK的区别
MOVE | SHRINK(仅对ASSM有效) | |
本质 | move实际上是block级别的数据块拷贝,对表进行move后,该表所在blockID会发生改变数据的rowID自然也会发生改变,但是数据在table中的存储顺序并没有发生改变 | shrink是对行数据进行移动。对表进行shrink后,部分行数据的rowID发生了变化,而table所位于的block区域的位置却没有发生变化。 |
重建索引 | 需要重建 | 可以通过cascade关键字重建 |
锁 | TM(exclusive) | TM(SX) |
空间要求 | 需要有原表大的空闲空间 | 不需要额外的空间 |
效果 | 压缩后会回收空间 | 压缩后会回收空间 |
详细例子见下面测试。
(七)高水位问题测试
(8.1)测试目的:
1.了解Oracle统计信息的概念;
2.测试使用delete与truncate删除数据对HWM的影响[主要目的]
(8.2)主要步骤
(1)创建表test01
create table test01( ID number,name varchar(15));这个时候,去查看表与段的参数
sqlselect 2 dt.table_name,3 dt.blocks,1)">4 dt.empty_blocks 5 from 6 dba_tables dt 7 where 8 dt.table_name = 'TEST01'; table_name BLOCKS EMPTY_BLOCKS---------------------------- ---------- ------------TEST01 0 0 sql> sql ds.segment_name,1)"> ds.segment_type,1)"> ds.header_file,1)">5 ds.header_block,1)"> ds.bytes,1)">7 ds.blocks,1)">8 ds.extents 9 from 10 dba_segments ds 11 where 12 ds.segment_name ; SEGMENT_name SEGMENT_TYPE header_file header_BLOCK BYTES BLOCKS EXTENTS----------- ------------------ ----------- ------------ ---------- ---------- ---------- exec dbms_stats.gather_table_stats(liJIAMAN',); PL/sql procedure successfully completed sql; SEGMENT_name SEGMENT_TYPE header_file header_BLOCK BYTES BLOCKS EXTENTS----------- ------------- ----------- ------------ ---------- ---------- ----------
通过以上结构可以看出,我在创建表后,去查看表信息,发现表拥有的blocks=0,以为是统计信息的问题,使用dbms_stats去重新收集表的基础信息,结果依然相同。然后查看该表段的信息,发现这个段并不存在。可以说明,数据库在创建表后,只存储了表的基本结构信息,只有在插入数据的时候,才会去分配区。
此时由于未分配数据块,也就不存在高水位线的问题。
(2)我们往test01里面插入10000条数据
sqldeclare 2 i number :=1; 3 begin loop 5 if i > 10000 6 then 7 exit8 end if9 insert into test01 values(i,1)">euvcg); 10 i:=i+; 11 end loop; 12 commit13 14 PLprocedure successfully completed
再去看一下表与段的统计信息
; table_name BLOCKS EMPTY_BLOCKS--------- ---------- ------------TEST01 ; SEGMENT_name SEGMENT_TYPE header_file header_BLOCK BYTES BLOCKS EXTENTS---------- ------------------ ----------- ------------ ---------- ---------- ----------TEST01 table 6 162 262144 32 4
表test01的blocks依然为0,我们使用dbms_stats重新收集统计信息,
sql> exec dbms_stats.gather_table_stats('liJIAMAN','TEST01');
PL/sql procedure successfully completed
sql---------------------------- ---------- ------------TEST01 28 sql4
收集统计信息后,我们对段进行分析,插入10000条数据,oracle一共分配了4个区,每个区包含8个数据块,每个数据块大小为8KB。此时,表的统计数据已经有了,但是表的Blocks与段的Blocks数量不同,这是什么引起的呢?通过查看两个blocks栏位的定义,可以看到:
dba_tables.blocks:该表已经使用的数据块的数量(Number of used data blocks in the table);
dba_segments.blocks:该段中数据块的总数(Size,in Oracle blocks,of the segment)。
也就是说还有4个数据块还未使用。
可以使用ANALYZE进行统计
> analyze table TEST01 compute statistics; table analyzed sql4经过分析,dba_tables统计的数据块与dba_segments统计的数据块数量相同了。
此时的高水位线应该如下:
(3)删除test01里面的全部数据,重新统计信息,发现数据块并没有被回收释放。这些数据块(dba_tables.blocks=28)曾经拥有过数据,但是现在数据已被删除。
delete from test01; 10000 rows deleted sqlCommit complete sqltable test01 sql----------- ------------------ ----------- ------------ ---------- ---------- ----------TEST01 4此时的高水位线应该如下:
黑色(used space)里面目前并没有数据,它仅仅代表曾经被使用过,白色(unused space)代表这些块已经分配给了test01段,但是还未使用过。
(4)测试完了delete,接下来测试truncate
truncate test01; truncated truncate后直接查询,发现表的统计信息依然未变化,而段的数据块已经回收了sql; SEGMENT_name SEGMENT_TYPE header_file header_BLOCK BYTES BLOCKS EXTENTS------------ ------------------ ----------- ------------ ---------- ---------- ----------TEST01 162 65536 8 1 执行dbms_stats重新收集统计信息,发现表的blocks已经为0,但是表的blocks与段的blocks并不相等sql再使用ANALYZE进行分析,表的empty blocks为8,与段的blocks相等sql analyzed sql1可以发现,truncate后,表的空间已经回收,但是并不等于0,而是一个extent的大小。此时高水位线为:
至于8个数据块是否有一个被使用(segment header),由于个人能力有限,无法进行分析 –_-
(8.3)结论:通过测试,delete无法降低高水位线,truncate可以。
(八)shrink与move测试
(9.1)测试目的:
1.测试shrink与move的区别,主要是第(七)点列出的区别
(9.2)测试步骤
(1)创建测试表,插入数据,分析表,查看统计信息
创建表sql test02 ( 3 ID 4 name ) ); created 插入1000万条数据sql10000000 into test02 successfully completed Executed in 185.125 seconds 创建索引sqlindex test02_IDx on test02 (ID,name); Index created Executed 17.172分析表sqlTEST023.921 seconds sqltable test02 analyzed Executed 39.11 seconds查看分析结果sql---------------------------- ---------- ------------TEST02 23357 195 Executed 0.078 secondssql----------- ------------------ ----------- ------------ ---------- ---------- ----------TEST02 130 192937984 23552 940.078 seconds可以看到。test02一共占用了94个extents,23552个数据块。其中23357个数据块有数据,195个数据块空闲。
接下来,我们先查看表的信息,这里截取了部分结果。在这里,我们需要了解ROWID的作用,rowID是数据在oracle储存中的具体位置,1-6位为object ID,7-9位为file_ID,10-15位代表block ID,16-18位为row number。在下面结果中,前5条数据在AAAACD块中,后6条数据在AAAACE块中。我们取出一个block,查看其数据:
select from test02 where rowID like AAASNnAAGAAAACM%; ID name-------- --------------- 2912 euvcg 291329142915 euvcg ... ... 33943395 euvcg 484 rows selected(2)删除test02的一半数据,数据块并没有释放,执行shrink *** 作
删除500万条数据sqldelete test02 where ID = i; /经过查看,数据块未释放激活行移动sqlalter test02 enable row movement; altered Executed 执行shrink *** 作 sqltable test02 shrink space cascade234.593 seconds需要注意的是,在执行shrink的过程中,在表上是有锁存在的,在表上存在3级锁(SX)
from v$lock where type in (TMTX); SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK- ---- ---------- ---------- ---------- ---------- ---------- ---------- 30 TM 74597 0 3 0 178 0 30 TX 327684 1294 327699 994 0(3)分析数据,查看表信息
; analyzedsql; table_name BLOCKS EMPTY_BLOCKS-------- ---------- ------------TEST02 11648 152130 96665600 11800 83在执行shrink之后,我们的数据块使用量由原来的23552减少为11800。
(4)再次查看上面数据块中的数据,可以看出在执行了shrink之后,该数据块中的数据发生了变化。对于该块,原来的数据保持不变,但是在已经删除数据的空间中,有其它块的数据插入了进来。
4050405229164054338833903392399 rows selected(9.3)结论
1.shrink是对行数据进行移动。对表进行shrink后,部分行数据的rowID发生了变化,而table所位于的block区域的位置却没有发生变化;
2.shrink产生TM(SX)锁及TX锁。
(9.4)对shrink有了一定的了解,我们再来看一下move
创建表 test03( ID ));插入数据sqlinto test03 successfully completed 统计信息sqltable test03 analyzed 查看统计信息sqlTEST03---------------------------- ---------- ------------TEST03 ---------- ------------------ ----------- ------------ ---------- ---------- ----------TEST03 146 4取其中一个数据块,查看存储的信息
select rowID,ID,name from test03 AAASNxAAGAAAACY%; ROWID ID name---------------- ---------- ---------------AAASNxAAGAAAACYAAA 3880 euvcgAAASNxAAGAAAACYAAC 3882 euvcgAAASNxAAGAAAACYAAE 3884 euvcgAAASNxAAGAAAACYAAG 3886 euvcgAAASNxAAGAAAACYAAI 3888 euvcgAAASNxAAGAAAACYAAK 3890 euvcgAAASNxAAGAAAACYAAM 3892 euvcgAAASNxAAGAAAACYAAO 3894 euvcgAAASNxAAGAAAACYAAQ 3896 euvcg… … …
执行move *** 作
test03 move; altered sql14 ------------ ------------------ ----------- ------------ ---------- ---------- ----------TEST03 186 131072 16 2在move之前我们查看了数据块AAASNxAAGAAAACY的信息,一共有242行,在move之后,我们再去查看该数据块,发现没有数据存在。经过查看,ID=4340的行信息之前存在该数据块,我们可以去看一下目前该行数据存在哪个数据块,找到新的数据块之后查看数据。
查看了数据块AAASNxAAGAAAACY的信息,发现没有数据,说明数据已经转移到新的数据块中去了sql---------------- ---------- --------------- 先前的数据块中存在ID=4340这一行数据,我们看一下该行数据目前的rowIDsqlwhere ID4340; ROWID ID name---------------- ---------- ---------------AAASNyAAGAAAAC9AHf euvcg通过rowID,我们可以确定该行数据的新的数据块ID,查询该数据块信息sqlAAASNyAAGAAAAC9%;ROWID ID name---------------- ---------- ---------------... ... ...AAASNyAAGAAAAC9ADz 480 euvcgAAASNyAAGAAAAC9AD0 482 euvcgAAASNyAAGAAAAC9AD1 484 euvcgAAASNyAAGAAAAC9AD2 486 euvcgAAASNyAAGAAAAC9AD3 488 euvcgAAASNyAAGAAAAC9AD4 490 euvcgAAASNyAAGAAAAC9AD5 euvcgAAASNyAAGAAAAC9AD6 euvcgAAASNyAAGAAAAC9AD7 euvcgAAASNyAAGAAAAC9AD8 euvcgAAASNyAAGAAAAC9AD9 euvcgAAASNyAAGAAAAC9AD+ / euvcg... ... ...结论:1.move之后,与先前数据块信息进行对比,发现数据块信息发生了改变,数据已经移到了其它数据块中。多个数据块的信息合并到了同一个数据块,但是数据的顺序并没有发生改变,即数据在原块中的顺序是怎么样的,迁移到新数据块中还是这样的;
2.move之后,数据块的使用量减少了,说明move收缩空间,降低高水位;
参考文档:http://docs.oracle.com/cd/E11882_01/server.112/e40540/logical.htm#CNCPT89026
Oracle运维最佳实践-上
http://blog.csdn.net/wyzxg/article/details/5631721
总结以上是内存溢出为你收集整理的[Oracle]高水位标记(HWM)全部内容,希望文章能够帮你解决[Oracle]高水位标记(HWM)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)