在Oracle 11g中,Advanced Compression是一个重要引入的新特性。Advanced Compression针对OLTP下的数据对象、Dataguard Redo Log等进行了较大程度的优化。在笔者之前的文章中,也针对此项特性进行了浅析。
目前,还有很多系统是运行在Oracle 10g乃至9i下,对这些系统而言,Oracle压缩有一些什么特性呢?本篇一起来探讨。
1、环境准备
我们选择Oracle 10gR2作为环境,同时准备原始数据表t_source,作为参照对象。
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
CORE10.2.0.1.0Production
准备数据,观察在未使用10g压缩特性情况下,数据空间使用情况。
sql> create table t_source as select * from dba_objects where wner='SCOTT' or wner='SYSMAN';
Table created
sql> select count(*) from t_source;
COUNT(*)
----------
1367
sql> exec dbms_stats.gather_table_stats(user,'T_SOURCE',cascade => true);
PL/sql procedure successfully completed
--段级别空间使用分析
sql> select HEADER_FILE,HEADER_BLOCK,BYTES,BLOCKS,EXTENTS from dba_segments where wner='SCOTT' and segment_name='T_SOURCE';
HEADER_FILE HEADER_BLOCKBYTESBLOCKSEXTENTS
----------- ------------ ---------- ---------- ----------
419196608243
sql> select NUM_ROWS,Compression from dba_tables where wner='SCOTT' and table_name='T_SOURCE';
NUM_ROWSBLOCKS COMPRESSION
---------- ---------- -----------
136723DISABLED
在利用所有行rowid情况,分析每个数据块的平均容纳行数。
sql> select dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) bno,count(*) from t_source group by dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) order by bno;
FNOBNOCOUNT(*)
---------- ---------- ----------
42046
42176
42276
42374
42478
4410573
4410671
4410771
4410873
4410977
4411076
4411174
4411273
4411477
4411574
4411675
4411745
4411981
4412077
19 rows selected
sql> select EXTENT_ID,FILE_ID,BLOCK_ID,BLOCKS from dba_extents where wner='SCOTT' and segment_name='T_SOURCE';
EXTENT_IDFILE_IDBLOCK_IDBYTESBLOCKS
---------- ---------- ---------- ---------- ----------
0417655368–第一个分区
144105655368
244113655368
从上面准备的数据表t_source的情况看,在没有使用压缩的情况下分配三个分区共24个数据块。1367条记录分布在19个数据块上,平均每个数据块容纳大约70-80行记录。
2、压缩表建立实验
下面建立压缩数据表。在建表的第一分区分配的时候,就采用压缩方式进行。
sql> create table t_compresscompressas select * from t_source;
44123131072162
136711ENABLED
我们当创建数据表就指定compress选项,数据表创建后就是压缩属性的。相同的数据量,只分配了2个分区。下面看具体行的使用情况。
44124178
44125199
44126177
44127197
44128189
44129185
44130207
4413135
8 rows selected
具体行在块的分配上,只用到了8个数据块进行存储。平均每个数据块容纳数据行接近200行。
说明:当我们在创建数据表的时候,就指定了compress选项。那么直接进行CATS插入的时候,压缩功能开启。同时,压缩效果较优。
注意:我们这里面使用的是CATS方式插入数据,而不是日常OLTP方式。两种方式差异显著。
3、变化分配数据插入实验
CATS方式是一种“压实”的插入方式。如果我们在变化过程中改变了数据表的压缩选项,空间分配情况会如何呢?
我们首先准备一个数据表,非压缩状态下插入过一部分的数据。
--插入一部分数据;
sql> create table t_sample as select * from t_source where mod(object_id,2)=0;
sql> select count(*) from t_sample;
695
44139131072162
sql>select NUM_ROWS,Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE';
69513DISABLED
4414080
4414175
4414274
4414371
4414474
4414574
4414675
4414774
4414879
4414919
10 rows selected
分配情况和t_source的趋势相似。我们修改数据表属性。
sql> alter table t_sample compress;
Table altered
44139131072162
69513ENABLED
注意:此时我们修改了数据表属性,变化为compress。但是,现有数据并没有被压缩,而是保留为原有的情况。平均块容量为80左右个数据行,而非压缩下的上百行。
笔者此时猜想了一种可能,有没有在内部已经进行了空间重排,形成行链接模式。经过测试,发现没有行链接。而且在修改数据表compress属性的时候,执行时间也没有进行复杂变化的机会。
那么,我们接下来插入剩下的数据,使用OLTP方式。
sql> insert into t_sample select * from t_source where mod(object_id,2)=1;
672 rows inserted
sql> commit;
Commit complete
44139196608243
136723ENABLED
4415074
4415178
4415275
4416274
4416375
4416477
4416569
4416772
4416878
19 rows selected
注意:此时虽然是压缩模式,但是使用OLTP insert方式后,数据表空间并没有节省!新分配空间,依然是使用非压缩方式——这点可以从块行容量上看出来。
解决方法——Move操作
解决的方法,我们可以采用move移动。Move是一种对数据表物理存储进行重排的过程,相当于在另一个磁盘上进行数据表重新组织,对应的空间乃至段头都要发生变化。Move是我们经常使用的降低HWM的方法。
sql> alter table t_sample move;
44171131072162
44172173
44173173
44174170
44175179
44176173
44177166
44178182
44179151
结论,我们发现空间被压缩,块行容量增加。
上面的实验,告诉我们几个结论:
üCompress是数据段的一个属性。当我们单纯进行compress和nocompress切换的时候,数据已经分配空间是不会发生变化的;
ü即使在compress的数据表,当我们进行常规OLTP数据插入的时候,是不会应用压缩选项的;
üMove操作通过重新促使系统进行数据空间分配的配比,可以应用实现compress的结果——注意是结果,数据表被压缩!
下面我们通过几个极端情况实验,继续分析10gR2的Compression。
3、极端情况实验(1)
那么,上面我们验证数据compress选项切换无效,是不是和我们已经分配过的记录有关系呢?我们首先建立一张空表。
sql> create table t_sample1 as select * from t_source where 1=0;
sql>exec dbms_stats.gather_table_stats(user,'T_SAMPLE1',EXTENTS from dba_segments where wner='SCOTT' and segment_name='T_SAMPLE1';
441396553681
00DISABLED
我们创建空表,没有记录,但是默认有一个分区分配过来。
sql> alter table t_sample1 compress;
00ENABLED
sql> insert into t_sample1 select * from t_source;
1367 rows inserted
136720 ENABLED
依然是使用三个分区,依然是没有进行压缩。
sql> alter table t_sample1 move;
44187131072162
136711 ENABLED
结论:即使没有一行数据插入的情况下,我们使用compress的数据表,利用OLTP方式插入,也不能实现压缩。依然需要手工的压缩过程。
4、极端情况实验(2)
对实验数据表t_sample1继续插入数据时,新分配的数据块是可能应用压缩格式的。
此时,数据行会出现部分压缩的现象。
44187262144324
273431 ENABLED
4413883
4413985
4414083
4414181
4414284
4414379
4414479
4414883
4414983
4415088
4415188
4415227
44188193
44189184
44190184
44191177
44192188
44193199
44194199
4419543
4419684
4419782
4419886
4419982
4420090
25 rows selected
在我们持续增加数据的时候,会出现一定的压缩情况。
44211196608243
273419 ENABLED
44212193
44213184
44214184
44215177
44216188
44225199
44226199
44227191
44228191
44229178
44230198
44231174
44232185
44490199
4449194
15 rows selected
通过move过程,实现完全压缩。
5、实现压缩的insert方式
从上面一系列实验中,我们可以看出Oracle 10g Compression对OLTP方式插入数据压缩效果较差。但是,在进行Direct Insert方法的时候,Compression的效果是可以的。
sql> create table t_source as select * from dba_objects where wner='SYS';
45395314572838418
22946327DISABLED
新原数据表没有压缩,共占用384个块,18个extent分区。下面建立一个新的数据表t_compress,采用压缩配置。
--建立空数据表;
sql> create table t_compress as select * from dba_objects where 1=0;
00 DISABLED
开启压缩选项。
sql> alter table t_compress compress;
00 ENABLED
之后采用direct insert方式插入数据。
sql> insert /*+append */into t_compress select * from t_source;
22946 rows inserted
22946139ENABLED
46835209715225617
可见,在10R2中,压缩主要是针对那些稳定数据。如果操作是频繁的增加修改和删除的OLTP操作,压缩是不进行或者效果很差的。
6、结论
从上面的实验中,我们可以看出:Oracle 10R2中的压缩技术主要是针对稳定数据表而言的。如果数据表很大,而且不会频繁的进行增加修改和删除操作,我们推荐使用压缩功能。如果我们对一个压缩表进行OLTP方式操作,压缩效应是不明显的。只有在Direct Insert等特殊的操作中,压缩才能体现出来。
Oracle 11g带给我们的Advanced Compression新特性,其中的Compression For OLTP在一定程度上缓解了这个难题。
再次说明,我们的解决方案,要依据版本、效果和特性进行。