HelloDBA [English]
搜索Internet 搜索 HelloDBABA
  Oracle技术站。email: fuyuncat@gmail.com  MSN: fuyuncat@hotmail.com   acoug  acoug 

数据段压缩(Data Segment Compression)浅析

[English]

作者: fuyuncat

来源: www.HelloDBA.com

日期: 2005-08-07 14:50:13

分享到  新浪微博 腾讯微博 人人网 i贴吧 开心网 豆瓣 淘宝 推特 Facebook GMail Blogger Orkut Google Bookmarks

1.   什么是数据段压缩

数据段压缩,又称为“块级压缩”,是Oracle 9.2 中出现的新特性。他对于数据仓库和那些只需要读的大表来说很有用。数据段压缩可以使存储空间减少,又可以提高查询速度(需要读入的数据块更少)。

压缩可以在创建表时指定,也可以通过修改表来激活。

CREATE TABLE CMPTest ( a number,

                                      b varchar2(20),

                                      c char(20))

             TABLESPACE ASSMDEMO

             NOLOGGING

             COMPRESS

             PCTFREE 0;

 

ALTER TABLE CMPTest COMPRESS;

 

此外,还可以对表空间指定压缩。

CREATE TABLESPACE tbs_compress DATAFILE 'tbscomp01.dat' SIZE 20M

               DEFAULT COMPRESS STORAGE ( … );

 

 

对于不更新/删除的大数据表,可以使用压缩,也可以使用分区。最好办法就是将老的数据压缩在一个分区表中。举例:

ALTER TABLE MYPARTTABLE MOVE PARTITION JAN04 TABLESPACE COMP_DATA COMPRESS PCTFREE 0;

          修改过表后,还是需要执行压缩命令进行压缩。

ALTER TABLE MYPARTTABLE MODIFY PARTITION JAN04 REBUILD UNUSABLE LOCAL INDEXES;

 

          数据段压缩的另一个适用的地方就是物化视图,因为物化视图一般都是只读的。

CREATE MATERIALIZED VIEW LOG ON cmptest
   WITH ROWID
   INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW CMP_MV
    tablespace assmdemo
    nologging
    compress
    pctfree 0
    REFRESH WITH ROWID AS SELECT * FROM cmptest x;

 

ALTER MATERIALIZED VIEW CMP_MV COMPRESS;

          当物化视图被刷新的时候,数据会压缩。

 

数据压缩对于用户来说是透明的。用户还是使用原来的查询语句进行查询。

 

 

查看表、索引或者物化视图是否压缩,可以通过以下语句:

SELECT table_name, compression FROM dba_tables;

select table_name, index_name, compression from dba_indexes
SELECT table_name, partition_name, compression FROM dba_tab_partitions;

 

2.   压缩是如何实现的

·         通过将数据块中的重复数据消除来实现压缩。

但是这种压缩只会压缩重复的数据字段/记录数据,而不会对一条字段/记录内的重复数据进行压缩。

 

·         一个数据块中字段或记录的所有重复数据只在数据块的开始处存储一次,这个地方就被称为这个数据块的记号表(Symbol Table)。

对于长字符串来说,除非字符串完全匹配,否则不会被压缩。

 

·         那些重复的数据都被一个指向记号表的短指引所代替。

除了在开始处有记号表外,压缩数据块和普通数据块都一样的。

 

·         只有当数据块被直接/批量载入/插入时,Oracle才会压缩数据。直接载入数据的语句有以下几种方式:

·         通过使用APPEND提示插入数据

·         通过使用PARALLEL提示插入数据(并行查询)

·         CREATE TABLE AS

·         SQL*LOAD时使用DIRECT LOAD

 

通过普通的INSERT语句插入数据时,是不会压缩数据的。

 

数据库中已有也可以通过ALTER TABLE … MOVE来压缩。这一操作会给表加上一个排他锁以阻止任何其他更新、插入操作。

如果这种方式不合适,可以使用Oracle的在线重整工具(dbms_redefinition包)来实现。

 

·         压缩数据可以通过INSERT, UPDATEDELETE命令操作,但是,没有使用批量插入或载入方式的数据不会被压缩。

数据段压缩比较适用于那些不要更新和删除数据的大表。如果对已经压缩的数据进行了UPDATE/DELETE操作,将结束对数据的压缩,从而占用更多的空间——在UPDATE时,Oracle会解压缩数据行,重新插入数据;而DELETE会充满那些空闲空间,使空闲空间不够插入下一条数据。直接载入数据的插入方式一般在高水位(HWM)以上载入数据。

压缩表测试:

SQL> CREATE TABLE cmptest(a NUMBER,

  2                       b VARCHAR2(20),

  3                       c CHAR(20))

  4         tablespace

  5         assmdemo

  6         nologging

  7         pctfree 0;

 

Table created.

 

SQL> BEGIN

  2    FOR i IN 1 .. 10000 LOOP

  3      INSERT INTO cmptest VALUES (mod(i,10), to_char(mod(i,10) * 1000), to_char(mod(i,10) * 1000));

  4    END LOOP;

  5    COMMIT;

  6  END;

  7  /

 

PL/SQL procedure successfully completed.

 

SQL> CREATE TABLE cmptest2

  2         tablespace

  3         assmdemo

  4         nologging

  5         compress

  6         pctfree 0

  7    AS

  8    select * from cmptest;

 

Table created.

 

SQL> select sum(bytes) from dba_segments where segment_name = 'CMPTEST';

 

SUM(BYTES)

----------

    393216

 

SQL> select sum(bytes) from dba_segments where segment_name = 'CMPTEST2';

 

SUM(BYTES)

----------

    196608

 

3.   数据压缩的限制

要注意,数据段压缩存在以下限制:

·         不可以对一个索引组织表、溢出段或一个溢出段的分区、索引组织表的映射表指定数据段压缩;

·         不可以对hash分区、listhash子分区指定数据段压缩;

·         不可以对一个EXTERNAL表指定数据段压缩;

·         一旦一个对象被压缩了,就不能再改变它的结构了。

SQL> alter table cmptest2 add (d number);

alter table cmptest2 add (d number)

                          *

ERROR at line 1:

ORA-00604: error occurred at recursive SQL level 1

ORA-06502: PL/SQL: numeric or value error: character string buffer too small

ORA-06512: at line 8

ORA-22856: cannot add columns to object tables

要避免这种错误,只有先将表EXPORT出来,然后使用不带COMPRESS参数的方式重建表,再将数据IMPORT进去。

 

4.   压缩数据块德的存储结构:

找出数据块,做dump:

SQL> select file_id, block_id, blocks from dba_extents where

  2  segment_name='CMPTEST2' and owner='HR';

 

   FILE_ID   BLOCK_ID     BLOCKS

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

        61         89          8

        61         97          8

        61        105          8

 

SQL> alter system dump datafile 61 block 92;

 

System altered.

 

下面就是DUMP出来的数据块内容:

Start dump data blocks tsn: 60 file#: 61 minblk 92 maxblk 92

buffer tsn: 60 rdba: 0x0f40005c (61/92)

scn: 0x0000.a0b3cabb seq: 0x02 flg: 0x04 tail: 0xcabb0602

frmt: 0x02 chkval: 0x08cc type: 0x06=trans data

Block header dump:  0x0f40005c

 Object id on Block? Y

 seg/obj: 0x3727  csc: 0x00.a0b3cab5  itc: 3  flg: E  typ: 1 - DATA

     brn: 0  bdba: 0xf400059 ver: 0x01

     inc: 0  exflg: 0

 

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.a0b3cab5

0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

data_block_dump,data header at 0x337107c

===============

tsiz: 0x1f80

hsiz: 0x5b0

pbl: 0x0337107c

bdba: 0x0f40005c

     76543210

flag=-0------

ntab=2

nrow=707

frre=-1

fsbo=0x5b0

fseo=0x10a7

avsp=0x13

tosp=0x13

            r0_9ir2=0x0

            mec_kdbh9ir2=0xa

            r1_9ir2=0x0

                      76543210

            flag_9ir2=------OC

                        fcls_9ir2[4]={ 0 32768 32768 32768 }

                        perm_9ir2[3]={ 1 2 0 }

0x22:pti[0]    nrow=10        offs=0

0x26:pti[1]    nrow=697      offs=10

0x2a:pri[0]    offs=0x1f60

0x2c:pri[1]    offs=0x1f40

0x2e:pri[2]    offs=0x1f20

… …

0x5ac:pri[705]         offs=0x10ac

0x5ae:pri[706]         offs=0x10a7

block_row_dump:

tab 0, row 0, @0x1f60

tl: 32 fb: --H-FL-- lb: 0x0  cc: 3

col  0: [20]  31 30 30 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

col  1: [ 2]  c1 02

col  2: [ 4]  31 30 30 30

bindmp: 00 46 03 dc 31 30 30 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ca c1 02 cc 31 30 30 30

tab 0, row 1, @0x1f40

tl: 32 fb: --H-FL-- lb: 0x0  cc: 3

col  0: [20]  32 30 30 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

col  1: [ 2]  c1 03

col  2: [ 4]  32 30 30 30

bindmp: 00 46 03 dc 32 30 30 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ca c1 03 cc 32 30 30 30

… …

tab 1, row 0, @0x1e3f

tl: 5 fb: --H-FL-- lb: 0x0