之前的两篇我们分别介绍了以下两部分内容,感兴趣的朋友可以去看一下:
基础篇:http://blog.csdn.net/badly9/article/details/49746825
加载数据到IM:http://blog.csdn.net/badly9/article/details/49777993
在CREATE或者ALTER时使用MEMCOMPRESS sub-clause可以设置表、分区和列水平上的压缩方式。举例说明,对于单个表,出于业务考虑,可能有的列更看重查询速度,有些则不在意查询速度更在意占用空间的大小,这时候对于不同的列则可以采用不同的压缩方式。
默认的压缩方式为MEMCOMPRESS FOR QUERY LOW。在这种压缩方式下,Oracle的读取速度最快,因为在这种压缩方式下,Oracle不需要解压缩就可以直接读取数据,比NO COMPRESS都要更快。其他压缩方式下,比如FOR QUREY HIGH和FOR CAPACITY,使用了其他的压缩算法,Oracle需要解压缩之后才能查看数据。下面列出了IM所有的压缩方式:
NO MEMCOMPRESS:数据加载过程中不进行任何压缩。
MEMCOMPRESS FOR DML:针对DML操作进行的最小程度的压缩以保证性能。
MEMCOMPRESS FOR QUERY LOW:针对查询性能优化的压缩方式(default)
MEMCOMPRESS FOR QUERY HIGH:除了查询性能也平衡了存储空间,但更偏向查询性能。
MEMCOMPRESS FOR CAPACITY LOW:平衡了性能与空间节省方面,但是更偏向于空间节省。
MEMCOMPRESS FOR CAPACITY HIGH:只从空间节省出发进行优化
在对表开启IM后,如果没有指定压缩级别则为默认压缩级别,为FOR QUERY LOW
实验过程如下:
1.创建测试表SALES_INM
SQL> CREATE TABLE SALES_INM INMEMORY AS SELECT * FROM SALES;
Table created.
2.查看测试表SALES_INM表的IM属性:
SQL> COL SEGMENT_NAME FORMAT A30
SQL> SELECT SEGMENT_NAME, INMEMORY, INMEMORY_COMPRESSION FROM
2 USER_SEGMENTS WHERE SEGMENT_NAME = 'SALES_INM';
SEGMENT_NAME INMEMORY INMEMORY_COMPRESS
------------------------------ -------- -----------------
SALES_INM ENABLED FOR QUERY LOW
可以看到此时的默认压缩级别为FOR QUERY LOW。
3.通过查询将表加载到IM中。
SQL> SELECT COUNT(*) FROM SALES_INM;
COUNT(*)
----------
918843
SQL> COL OWNER FORMAT A20
SQL> SELECT OWNER, SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED
2 FROM V$IM_SEGMENTS WHERE SEGMENT_NAME = 'SALES_INM';
OWNER SEGMENT_NAME POPULATE_ BYTES_NOT_POPULATED
-------------------- -------------------- --------- -------------------
BADLY9 SALES_INM COMPLETED 0
4.查看压缩之后的表大小
SQL> SELECT V.OWNER, V.SEGMENT_NAME,
2 V.BYTES ORIG_SIZE,
3 V.INMEMORY_SIZE IN_MEM_SIZE,
4 V.BYTES/V.INMEMORY_SIZE COMP_RATIO
5 FROM V$IM_SEGMENTS V
6 WHERE SEGMENT_NAME = 'SALES_INM';
OWNER SEGMENT_NAME ORIG_SIZE IN_MEM_SIZE COMP_RATIO
-------------------- -------------------- ---------- ----------- ----------
BADLY9 SALES_INM 12582912 8585216 1.46564885
该表在disk中大小为12582912字节,加载压缩后为8585216字节,比例为为1.466:1
刚才测试了QUERY LOW压缩级别,现在来测一下CAPACITY HIGH的压缩级别。
实验过程如下:
1.创建测试表SALES_INM2,压缩级别为CAPACITY HIGH,PRIORITY为HIGH。
SQL> CREATE TABLE SALES_INM2 INMEMORY MEMCOMPRESS FOR CAPACITY HIGH
2 PRIORITY HIGH AS SELECT * FROM SALES;
Table created.
2.确认一下SALES_INM2的IM属性
SQL> COL SEGMENT_NAME FORMAT A20
SQL> SELECT SEGMENT_NAME, INMEMORY, INMEMORY_PRIORITY,
2 INMEMORY_COMPRESSION FROM USER_SEGMENTS
3 WHERE SEGMENT_NAME = 'SALES_INM2';
SEGMENT_NAME INMEMORY INMEMORY INMEMORY_COMPRESS
-------------------- -------- -------- -----------------
SALES_INM2 ENABLED HIGH FOR CAPACITY HIGH
3.确认SALES_INM2已经加载完毕
SQL> COL OWNER FORMAT A20
SQL> SELECT OWNER, SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED
2 FROM V$IM_SEGMENTS WHERE SEGMENT_NAME = 'SALES_INM2';
OWNER SEGMENT_NAME POPULATE_ BYTES_NOT_POPULATED
-------------------- -------------------- --------- -------------------
BADLY9 SALES_INM2 COMPLETED 0
4.查看压缩比例
SQL> SELECT V.OWNER, V.SEGMENT_NAME,
2 V.BYTES ORIG_SIZE,
3 V.INMEMORY_SIZE IN_MEM_SIZE,
4 V.BYTES/V.INMEMORY_SIZE COMP_RATIO
5 FROM V$IM_SEGMENTS V
6 WHERE SEGMENT_NAME = 'SALES_INM2';
OWNER SEGMENT_NAME ORIG_SIZE IN_MEM_SIZE COMP_RATIO
-------------------- -------------------- ---------- ----------- ----------
BADLY9 SALES_INM2 12582912 3342336 3.76470588
可以看到CAPACITY HIGH压缩级别,该表在disk中大小为12582912,压缩后为3342336,比例为3.76:1。
对于各个压缩级别的压缩测试不再一一展示,针对我使用的这张表的在disk中大小与加载压缩后比例对比如下:
NO MEMCOPRESS:1:2.65104167
FOR DML:1:2.23
FOR QUERY LOW:1:0.68
FOR QUERY HIGH:1:0.43
FOR CAPACITY LOW:1:0.34
FOR CAPACITY HIGH:1:0.26
在上面的实验中我们压缩针对的是整个表级别,事实上我们也可以针对不同的列使用不同的压缩级别。
实验过程如下:
1.修改CUSTOMERS表各列压缩级别,其中各个列压缩级别如下:
CUT_FIRST_NAME和CUST_LAST_NAME的压缩级别为QUERY HIGH
CUST_STREET_ADDRESS压缩级别为CAPACITY LOW
CUST_CITY 和CUST_STATE_PROVINCE压缩级别为No compression
其他列压缩级别为默认。
SQL> ALTER TABLE CUSTOMERS INMEMORY
2 INMEMORY MEMCOMPRESS FOR QUERY HIGH (CUST_FIRST_NAME,
3 CUST_LAST_NAME)
4 INMEMORY MEMCOMPRESS FOR CAPACITY LOW (CUST_STREET_ADDRESS)
5 INMEMORY NO MEMCOMPRESS (CUST_CITY, CUST_STATE_PROVINCE);
Table altered.
2.查看各列压缩级别
SQL> SET LINES 100;
SELECT TABLE_NAME, COLUMN_NAME, INMEMORY_COMPRESSION
FROM V$IM_COLUMN_LEVEL
SQL> 2 3 WHERE TABLE_NAME = 'CUSTOMERS';
TABLE_NAME COLUMN_NAME INMEMORY_COMPRESSION
------------------------------- ------------------------------- --------------------------
CUSTOMERS CUST_ID DEFAULT
CUSTOMERS CUST_FIRST_NAME FOR QUERY HIGH
CUSTOMERS CUST_LAST_NAME FOR QUERY HIGH
CUSTOMERS CUST_GENDER DEFAULT
CUSTOMERS CUST_YEAR_OF_BIRTH DEFAULT
CUSTOMERS CUST_MARITAL_STATUS DEFAULT
CUSTOMERS CUST_STREET_ADDRESS FOR CAPACITY LOW
CUSTOMERS CUST_POSTAL_CODE DEFAULT
CUSTOMERS CUST_CITY NO MEMCOMPRESS
CUSTOMERS CUST_CITY_ID DEFAULT
CUSTOMERS CUST_STATE_PROVINCE NO MEMCOMPRESS
CUSTOMERS CUST_STATE_PROVINCE_ID DEFAULT
CUSTOMERS COUNTRY_ID DEFAULT
CUSTOMERS CUST_MAIN_PHONE_NUMBER DEFAULT
CUSTOMERS CUST_INCOME_LEVEL DEFAULT
CUSTOMERS CUST_CREDIT_LIMIT DEFAULT
CUSTOMERS CUST_EMAIL DEFAULT
CUSTOMERS CUST_TOTAL DEFAULT
CUSTOMERS CUST_TOTAL_ID DEFAULT
CUSTOMERS CUST_SRC_ID DEFAULT
CUSTOMERS CUST_EFF_FROM DEFAULT
CUSTOMERS CUST_EFF_TO DEFAULT
CUSTOMERS CUST_VALID DEFAULT
23 rows selected.
3.加载该表到IM中。
SQL> EXEC DBMS_INMEMORY.REPOPULATE('BADLY9,'CUSTOMERS', FORCE=>TRUE);
PL/SQL procedure successfully completed.
4.确认该表已经加载到IM中
SQL> SELECT SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED
2 FROM V$IM_SEGMENTS WHERE SEGMENT_NAME = 'CUSTOMERS';
SEGMENT_NAME POPULATE_ BYTES_NOT_POPULATED
-------------------- --------- -------------------
CUSTOMERS COMPLETED 0
5.修改表上列的压缩属性。
SQL> ALTER TABLE CUSTOMERS INMEMORY
2 INMEMORY MEMCOMPRESS FOR QUERY LOW (CUST_FIRST_NAME)
3 INMEMORY MEMCOMPRESS FOR CAPACITY LOW (CUST_MAIN_PHONE_NUMBER)
4 INMEMORY NO MEMCOMPRESS (CUST_STREET_ADDRESS);
Table altered.
6.查看该表上各列的压缩属性
SQL> SET LINES 100;
SQL> SELECT TABLE_NAME, COLUMN_NAME, INMEMORY_COMPRESSION
2 FROM V$IM_COLUMN_LEVEL
3 WHERE TABLE_NAME = 'CUSTOMERS';
TABLE_NAME COLUMN_NAME INMEMORY_COMPRESSION
------------------------------- ------------------------------- --------------------------
CUSTOMERS CUST_ID DEFAULT
CUSTOMERS CUST_FIRST_NAME FOR QUERY LOW
CUSTOMERS CUST_LAST_NAME FOR QUERY HIGH
CUSTOMERS CUST_GENDER DEFAULT
CUSTOMERS CUST_YEAR_OF_BIRTH DEFAULT
CUSTOMERS CUST_MARITAL_STATUS DEFAULT
CUSTOMERS CUST_STREET_ADDRESS NO MEMCOMPRESS
CUSTOMERS CUST_POSTAL_CODE DEFAULT
CUSTOMERS CUST_CITY NO MEMCOMPRESS
CUSTOMERS CUST_CITY_ID DEFAULT
CUSTOMERS CUST_STATE_PROVINCE NO MEMCOMPRESS
CUSTOMERS CUST_STATE_PROVINCE_ID DEFAULT
CUSTOMERS COUNTRY_ID DEFAULT
CUSTOMERS CUST_MAIN_PHONE_NUMBER FOR CAPACITY LOW
CUSTOMERS CUST_INCOME_LEVEL DEFAULT
CUSTOMERS CUST_CREDIT_LIMIT DEFAULT
CUSTOMERS CUST_EMAIL DEFAULT
CUSTOMERS CUST_TOTAL DEFAULT
CUSTOMERS CUST_TOTAL_ID DEFAULT
CUSTOMERS CUST_SRC_ID DEFAULT
CUSTOMERS CUST_EFF_FROM DEFAULT
CUSTOMERS CUST_EFF_TO DEFAULT
CUSTOMERS CUST_VALID DEFAULT
23 rows selected.
7.再次查看该表是否被加载到IM中。
SQL> SELECT SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED
2 FROM V$IM_SEGMENTS WHERE SEGMENT_NAME = 'CUSTOMERS';
no rows selected
可以看到现在该表已经从IM中flush出去了,因为改变了该表的压缩属性,而且没有设置PRIORITY,也没有进行重新加载,所以该表已被刷出IM区域。等待重新加载。
在之前的实验中我们也测试过可以在tablespace层面设置inmemory clause,那么针对tablespace层面进行压缩设置当然也要实验一下啦。
实验过程如下:
1.查看表空间目前IM属性
SQL> SELECT TABLESPACE_NAME, DEF_INMEMORY, DEF_INMEMORY_COMPRESSION
2 FROM DBA_TABLESPACES;
TABLESPACE_NAME DEF_INME DEF_INMEMORY_COMP
------------------------------ -------- -----------------
SYSTEM DISABLED
SYSAUX DISABLED
UNDOTBS1 DISABLED
TEMP DISABLED
USERS DISABLED
RTL_DATA DISABLED
TBS_TEST DISABLED
7 rows selected.
2.更改表空间属性
SQL> ALTER TABLESPACE TBS_TEST DEFAULT INMEMORY MEMCOMPRESS FOR CAPACITY
2 HIGH PRIORITY HIGH;
Tablespace altered.
3.查看表空间IM属性
SQL> SELECT TABLESPACE_NAME, DEF_INMEMORY,
2 DEF_INMEMORY_COMPRESSION, DEF_INMEMORY_PRIORITY
3 FROM DBA_TABLESPACES WHERE TABLESPACE_NAME = 'TBS_TEST';
TABLESPACE_NAME DEF_INME DEF_INMEMORY_COMP DEF_INME
------------------------------ -------- ----------------- --------
TBS_TEST ENABLED FOR CAPACITY HIGH HIGH
4.创建测试表SALES_INM3不添加IM参数,SALES_INM4添加IM参数
SQL> CREATE TABLE SALES_INM3 AS SELECT * FROM SALES;
Table created.
SQL> CREATE TABLE SALES_INM4 INMEMORY MEMCOMPRESS FOR QUERY HIGH AS
2 SELECT * FROM SALES;
Table created.
5.查询两张测试表的IM压缩参数
SQL> COL SEGMENT_NAME FORMAT A20
SQL> SELECT SEGMENT_NAME, INMEMORY, INMEMORY_PRIORITY,
2 INMEMORY_COMPRESSION FROM USER_SEGMENTS WHERE SEGMENT_NAME IN
3 ('SALES_INM3','SALES_INM4');
SEGMENT_NAME INMEMORY INMEMORY INMEMORY_COMPRESS
-------------------- -------- -------- -----------------
SALES_INM3 ENABLED HIGH FOR CAPACITY HIGH
SALES_INM4 ENABLED NONE FOR QUERY HIGH
注意:不知道大家是否还记得前边的文章在介绍INMEMORY_CLAUSE_DEFAULT的时候,如果创建表的时候没有设置PRIORITY,那么会自动设置为INMEMORY_CLAUSE_DEFAULT的设置,和其他参数进行一个叠加。但是如果在tablespace级别上设置了IM属性,创建表如果使用了IM属性,是不会有叠加效果的,而是单纯使用创建表时语句指定的IM属性。
7.查询一边SALES_INM4,将表加载到IM中。
SQL> SELECT COUNT(*) FROM SALES_INM4;
COUNT(*)
----------
918843
8.确认两张表都已经加载完成
SQL> COL OWNER FORMAT A20
SQL> SELECT OWNER, SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED
2 FROM V$IM_SEGMENTS WHERE SEGMENT_NAME IN ('SALES_INM3',
3 'SALES_INM4');
OWNER SEGMENT_NAME POPULATE_ BYTES_NOT_POPULATED
-------------------- -------------------- --------- -------------------
BADLY9 SALES_INM3 COMPLETED 0
BADLY9 SALES_INM4 COMPLETED 0
9.查看两张表压缩后的大小
SQL> SELECT V.SEGMENT_NAME,
2 V.INMEMORY_COMPRESSION,
3 V.BYTES ORIG_SIZE,
4 V.INMEMORY_SIZE IN_MEM_SIZE,
5 V.BYTES/V.INMEMORY_SIZE COMP_RATIO
6 FROM V$IM_SEGMENTS V
7 WHERE SEGMENT_NAME IN ('SALES_INM3','SALES_INM4');
SEGMENT_NAME INMEMORY_COMPRESS ORIG_SIZE IN_MEM_SIZE COMP_RATIO
-------------------- ----------------- ---------- ----------- ----------
SALES_INM3 FOR CAPACITY HIGH 12582912 2228224 5.64705882
SALES_INM4 FOR QUERY HIGH 12582912 5439488 2.31325301
最后将tablespace重新改为NO INMEMORY,这两张表的IM属性不变,这里就不再贴实验过程。也就是说tablespace的修改只针对后来新建的表生效。
在对一张表使用COMPRESSION clause进行IM压缩级别设置之前,我们可以通过Oracle的COMPRESSION ADVISOR对表放入到IM中的大小进行提前计算。COMPRESSION ADVISOR是通过对于表中的数据进行采样,然后来分析压缩后所占的空间,所以相对来说还是非常精准的。
那么接下来我们通过DBMS_COMPRESSION.GET_COMPRESSION_RATIO对SALES_INM3和SALES_INM4放入到IM中的压缩比率进行预估。
实验过程如下:
1.通过下面的语句对SALES_INM3使用CAPCATITY HIGH级别进行压缩比率估算:
SET SERVEROUTPUT ON
DECLARE
l_blkcnt_cmp PLS_INTEGER;
l_blkcnt_uncmp PLS_INTEGER;
l_row_cmp PLS_INTEGER;
l_row_uncmp PLS_INTEGER;
l_cmp_ratio PLS_INTEGER;
l_comptype_str VARCHAR2(100);
BEGIN
dbms_compression.get_compression_ratio (
-- Input parameters
scratchtbsname => 'TBS_TEST',
ownname => 'BADLY9',
objname => 'SALES_INM4',
subobjname => NULL,
comptype => dbms_compression.comp_inmemory_capacity_high,
-- Output parameter
blkcnt_cmp => l_blkcnt_cmp,
blkcnt_uncmp => l_blkcnt_uncmp,
row_cmp => l_row_cmp,
row_uncmp => l_row_uncmp,
cmp_ratio => l_cmp_ratio,
comptype_str => l_comptype_str,
subset_numrows => dbms_compression.comp_ratio_allrows);
dbms_output.put_line('Comp. ratio (Capacity High):'||l_cmp_ratio);
END;
/
输出结果:
Comp. ratio (Capacity High):5
PL/SQL procedure successfully completed.
可以看到输出压缩倍数为5,对比我们前边实验结果为 5.64705882,可见这个压缩比例和实际的压缩比例有差距但相差不大。
2.对SALES_INM4表使用QUERY HIGH级别,预估加载到IM中之后的压缩比率:
SET SERVEROUTPUT ON
DECLARE
l_blkcnt_cmp PLS_INTEGER;
l_blkcnt_uncmp PLS_INTEGER;
l_row_cmp PLS_INTEGER;
l_row_uncmp PLS_INTEGER;
l_cmp_ratio PLS_INTEGER;
l_comptype_str VARCHAR2(100);
BEGIN
dbms_compression.get_compression_ratio (
-- Input parameters
scratchtbsname => 'TBS_TEST',
ownname => 'BADLY9',
objname => 'SALES_INM4',
subobjname => NULL,
comptype => dbms_compression.comp_inmemory_query_high,
-- Output parameter
blkcnt_cmp => l_blkcnt_cmp,
blkcnt_uncmp => l_blkcnt_uncmp,
row_cmp => l_row_cmp,
row_uncmp => l_row_uncmp,
cmp_ratio => l_cmp_ratio,
comptype_str => l_comptype_str,
subset_numrows => dbms_compression.comp_ratio_allrows);
dbms_output.put_line('Comp. ratio (Query High):'||l_cmp_ratio);
END;
/
输出结果为:
Comp. ratio (Query High):2
PL/SQL procedure successfully completed.
对比我们前边的实验结果为2.31325301。
自己实验的话只要把我标红的几个参数进行修改即可。