Oracle 10g数据表压缩的一些细节(上)

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

CORE     10.2.0.1.0       Production

 

 

准备数据,观察在未使用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_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4           19     196608         24          3

 

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SOURCE';

  NUM_ROWS     BLOCKS COMPRESSION

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

      1367         23 DISABLED

 

 

在利用所有行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;

 

       FNO        BNO   COUNT(*)

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

         4         20         46

         4         21         76

         4         22         76

         4         23         74

         4         24         78

         4       4105         73

         4       4106         71

         4       4107         71

         4       4108         73

         4       4109         77

         4       4110         76

         4       4111         74

         4       4112         73

         4       4114         77

         4       4115         74

         4       4116         75

         4       4117         45

         4       4119         81

         4       4120         77

19 rows selected

 

 

SQL> select EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS from dba_extents where wner='SCOTT' and segment_name='T_SOURCE';

 

 EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS

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

         0          4         17      65536          8 第一个分区

         1          4       4105      65536          8

         2          4       4113      65536          8

 

 

从上面准备的数据表t_source的情况看,在没有使用压缩的情况下分配三个分区共24个数据块。1367条记录分布在19个数据块上,平均每个数据块容纳大约70-80行记录。

 

2、压缩表建立实验

 

下面建立压缩数据表。在建表的第一分区分配的时候,就采用压缩方式进行。

 

 

SQL> create table t_compress compress as select * from t_source;

Table created

 

SQL> exec dbms_stats.gather_table_stats(user,'T_COMPRESS',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_COMPRESS';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4123     131072         16          2

 

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_COMPRESS';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

      1367         11 ENABLED

 

 

我们当创建数据表就指定compress选项,数据表创建后就是压缩属性的。相同的数据量,只分配了2个分区。下面看具体行的使用情况。

 

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_compress group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4124        178

         4       4125        199

         4       4126        177

         4       4127        197

         4       4128        189

         4       4129        185

         4       4130        207

         4       4131         35

 

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;

Table created

 

SQL> select count(*) from t_sample;

  COUNT(*)

----------

       695

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE',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_SAMPLE';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4139     131072         16          2

 

SQL>  select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE';

  NUM_ROWS     BLOCKS COMPRESSION

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

       695         13 DISABLED

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_sample group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4140         80

         4       4141         75

         4       4142         74

         4       4143         71

         4       4144         74

         4       4145         74

         4       4146         75

         4       4147         74

         4       4148         79

         4       4149         19

 

10 rows selected

 

 

分配情况和t_source的趋势相似。我们修改数据表属性。

 

 

SQL> alter table t_sample compress;

Table altered

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE',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_SAMPLE';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4139     131072         16          2

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

       695         13 ENABLED

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_sample group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4140         80

         4       4141         75

         4       4142         74

         4       4143         71

         4       4144         74

         4       4145         74

         4       4146         75

         4       4147         74

         4       4148         79

         4       4149         19

10 rows selected

 

 

注意:此时我们修改了数据表属性,变化为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

 

SQL> select count(*) from t_sample;

  COUNT(*)

----------

      1367

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE',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_SAMPLE';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4139     196608         24          3

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

      1367         23 ENABLED

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_sample group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4140         80

         4       4141         75

         4       4142         74

         4       4143         71

         4       4144         74

         4       4145         74

         4       4146         75

         4       4147         74

         4       4148         79

         4       4149         19

         4       4150         74

         4       4151         78

         4       4152         75

         4       4162         74

         4       4163         75

         4       4164         77

         4       4165         69

         4       4167         72

         4       4168         78

 

19 rows selected

 

 

注意:此时虽然是压缩模式,但是使用OLTP insert方式后,数据表空间并没有节省!新分配空间,依然是使用非压缩方式——这点可以从块行容量上看出来。

 

解决方法——Move操作

 

解决的方法,我们可以采用move移动。Move是一种对数据表物理存储进行重排的过程,相当于在另一个磁盘上进行数据表重新组织,对应的空间乃至段头都要发生变化。Move是我们经常使用的降低HWM的方法。

 

 

SQL> alter table t_sample move;

Table altered

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE',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_SAMPLE';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4171     131072         16          2

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE';

  NUM_ROWS     BLOCKS COMPRESSION

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

      1367         11 ENABLED

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_sample group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4172        173

         4       4173        173

         4       4174        170

         4       4175        179

         4       4176        173

         4       4177        166

         4       4178        182

         4       4179        151

 

8 rows selected

 

 

结论,我们发现空间被压缩,块行容量增加。

 

上面的实验,告诉我们几个结论:

 

ü        Compress是数据段的一个属性。当我们单纯进行compressnocompress切换的时候,数据已经分配空间是不会发生变化的;

ü        即使在compress的数据表,当我们进行常规OLTP数据插入的时候,是不会应用压缩选项的;

ü        Move操作通过重新促使系统进行数据空间分配的配比,可以应用实现compress的结果——注意是结果,数据表被压缩!

 

下面我们通过几个极端情况实验,继续分析10gR2Compression

Oracle 10g数据表压缩的一些细节(下)

下面我们通过几个极端情况实验,继续分析10gR2Compression

 

3、极端情况实验(1

 

那么,上面我们验证数据compress选项切换无效,是不是和我们已经分配过的记录有关系呢?我们首先建立一张空表。

 

 

SQL> create table t_sample1 as select * from t_source where 1=0;

Table created

 

SQL>  exec dbms_stats.gather_table_stats(user,'T_SAMPLE1',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_SAMPLE1';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4139      65536          8          1

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE1';

  NUM_ROWS     BLOCKS COMPRESSION

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

         0          0 DISABLED

 

 

我们创建空表,没有记录,但是默认有一个分区分配过来。

 

 

SQL> alter table t_sample1 compress;

Table altered

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE1';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

         0          0 ENABLED

 

SQL> insert into t_sample1 select * from t_source;

1367 rows inserted

 

SQL> commit;

Commit complete

 

SQL>  exec dbms_stats.gather_table_stats(user,'T_SAMPLE1',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_SAMPLE1';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4139     196608         24          3

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE1';

  NUM_ROWS     BLOCKS COMPRESSION

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

      1367         20 ENABLED

 

 

依然是使用三个分区,依然是没有进行压缩。

 

 

SQL> alter table t_sample1 move;

 

Table altered

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE1',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_SAMPLE1';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4187     131072         16          2

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE1';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

      1367         11 ENABLED

 

 

结论:即使没有一行数据插入的情况下,我们使用compress的数据表,利用OLTP方式插入,也不能实现压缩。依然需要手工的压缩过程。

 

 

4、极端情况实验(2

 

对实验数据表t_sample1继续插入数据时,新分配的数据块是可能应用压缩格式的。

 

 

SQL> insert into t_sample1 select * from t_source;

1367 rows inserted

 

SQL> commit;

Commit complete

 

 

此时,数据行会出现部分压缩的现象。

 

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE1',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_SAMPLE1';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4187     262144         32          4

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE1';

  NUM_ROWS     BLOCKS COMPRESSION

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

      2734         31 ENABLED

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_sample1 group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4138         83

         4       4139         85

         4       4140         83

         4       4141         81

         4       4142         84

         4       4143         79

         4       4144         79

         4       4148         83

         4       4149         83

         4       4150         88

         4       4151         88

         4       4152         27

         4       4188        193

         4       4189        184

         4       4190        184

         4       4191        177

         4       4192        188

         4       4193        199

         4       4194        199

         4       4195         43

         4       4196         84

         4       4197         82

         4       4198         86

         4       4199         82

         4       4200         90

 

25 rows selected

 

 

在我们持续增加数据的时候,会出现一定的压缩情况。

 

 

SQL> alter table t_sample1 move;

Table altered

 

SQL> exec dbms_stats.gather_table_stats(user,'T_SAMPLE1',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_SAMPLE1';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         4211     196608         24          3

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SAMPLE1';

  NUM_ROWS     BLOCKS COMPRESSION

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

      2734         19 ENABLED

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, count(*) from t_sample1 group by dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) order by bno;

 

       FNO        BNO   COUNT(*)

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

         4       4212        193

         4       4213        184

         4       4214        184

         4       4215        177

         4       4216        188

         4       4225        199

         4       4226        199

         4       4227        191

         4       4228        191

         4       4229        178

         4       4230        198

         4       4231        174

         4       4232        185

         4       4490        199

         4       4491         94

 

15 rows selected

 

 

通过move过程,实现完全压缩。

 

5、实现压缩的insert方式

 

从上面一系列实验中,我们可以看出Oracle 10g CompressionOLTP方式插入数据压缩效果较差。但是,在进行Direct Insert方法的时候,Compression的效果是可以的。

 

 

SQL> create table t_source as select * from dba_objects where wner='SYS';

Table created

 

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_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         5395    3145728        384         18

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_SOURCE';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

     22946        327 DISABLED

 

 

新原数据表没有压缩,共占用384个块,18extent分区。下面建立一个新的数据表t_compress,采用压缩配置。

 

--建立空数据表;

SQL> create table t_compress as select * from dba_objects where 1=0;

Table created

 

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

PL/SQL procedure successfully completed

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_COMPRESS';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

         0          0 DISABLED

 

 

开启压缩选项。

 

 

SQL> alter table t_compress compress;

Table altered

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_COMPRESS';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

         0          0 ENABLED

 

 

之后采用direct insert方式插入数据。

 

 

SQL> insert /*+append */into t_compress select * from t_source;

22946 rows inserted

 

SQL> commit;

Commit complete

 

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

PL/SQL procedure successfully completed

 

 

SQL> select NUM_ROWS, BLOCKS, Compression from dba_tables where wner='SCOTT' and table_name='T_COMPRESS';

 

  NUM_ROWS     BLOCKS COMPRESSION

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

     22946        139 ENABLED

 

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

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          4         6835    2097152        256         17

 

 

可见,10R2中,压缩主要是针对那些稳定数据。如果操作是频繁的增加修改和删除的OLTP操作,压缩是不进行或者效果很差的。

 

6、结论

 

从上面的实验中,我们可以看出:Oracle 10R2中的压缩技术主要是针对稳定数据表而言的。如果数据表很大,而且不会频繁的进行增加修改和删除操作,我们推荐使用压缩功能。如果我们对一个压缩表进行OLTP方式操作,压缩效应是不明显的。只有在Direct Insert等特殊的操作中,压缩才能体现出来。

 

Oracle 11g带给我们的Advanced Compression新特性,其中的Compression For OLTP在一定程度上缓解了这个难题。

 

再次说明,我们的解决方案,要依据版本、效果和特性进行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值