Oracle 10g資料表壓縮的一些細節(上)

realkid4發表於2012-03-25

 

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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-719482/,如需轉載,請註明出處,否則將追究法律責任。

相關文章