数据段压缩,又称为“块级压缩”,是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;
· 通过将数据块中的重复数据消除来实现压缩。
但是这种压缩只会压缩重复的数据字段/记录数据,而不会对一条字段/记录内的重复数据进行压缩。
· 一个数据块中字段或记录的所有重复数据只在数据块的开始处存储一次,这个地方就被称为这个数据块的记号表(Symbol
Table)。
对于长字符串来说,除非字符串完全匹配,否则不会被压缩。
· 那些重复的数据都被一个指向记号表的短指引所代替。
除了在开始处有记号表外,压缩数据块和普通数据块都一样的。
· 只有当数据块被直接/批量载入/插入时,Oracle才会压缩数据。直接载入数据的语句有以下几种方式:
· 通过使用APPEND提示插入数据
· 通过使用PARALLEL提示插入数据(并行查询)
· CREATE TABLE AS
· 在SQL*LOAD时使用DIRECT LOAD
通过普通的INSERT语句插入数据时,是不会压缩数据的。
数据库中已有也可以通过ALTER
TABLE … MOVE来压缩。这一操作会给表加上一个排他锁以阻止任何其他更新、插入操作。
如果这种方式不合适,可以使用Oracle的在线重整工具(dbms_redefinition包)来实现。
· 压缩数据可以通过INSERT,
UPDATE和DELETE命令操作,但是,没有使用批量插入或载入方式的数据不会被压缩。
数据段压缩比较适用于那些不要更新和删除数据的大表。如果对已经压缩的数据进行了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
3 INSERT INTO cmptest VALUES (mod(i,10), to_char(mod(i,10) * 1000), to_char(mod(i,10) *
1000));
4 END
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
要注意,数据段压缩存在以下限制:
· 不可以对一个索引组织表、溢出段或一个溢出段的分区、索引组织表的映射表指定数据段压缩;
· 不可以对hash分区、list或hash子分区指定数据段压缩;
· 不可以对一个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进去。
找出数据块,做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
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9650775/viewspace-920386/ ,如需转载,请注明出处,否则将追究法律责任。