ITPub博客

首页 > 数据库 > Oracle > 12c in memory option学习笔记一_基础篇

12c in memory option学习笔记一_基础篇

原创 Oracle 作者:talio 时间:2014-09-16 13:18:10 0 删除 编辑

Oracle 12c in memory选件通过在SGA中分配独立的内存区域(In Memory Area),对数据使用列式压缩存储来提高查询性能.

In Memory区的大小由参数inmemory_size控制, 该参数是一个静态参数, 修改后需要重启数据库方可生效.

In Memory内存区可分为两个子池,分别为1M pool和64K pool. 1M pool用于存储列式数据. 64K pool用于存储对象的元数据(metadata)和事务日志(transaction journal). 1M pool 中分配的内存块的大小为1M的整数倍,64K pool中分配的内存块大小均为64K。

v$inmemory_area视图有每个pool大小的详细信息:

SQL> select * from v$inmemory_area;
POOL                       ALLOC_BYTES USED_BYTES POPULATE_STATUS                CON_ID
-------------------------- ----------- ---------- -------------------------- ----------
1MB POOL                     854589440   10485760 DONE                                0
64KB POOL                    201326592     393216 DONE                                0 

In Memory区的数据装载(populating)

相对于磁盘或者闪存,内存资源毕竟成本更高,更为有限,所以需要将有限的资源分配给更需要的对象. Oracle新增了一个INMEMORY属性用于控制对象是否会被装载到In Memory区, 该属性可以定义在表 空间,表,分区甚至列级. Oracle In Memory白皮书中给出了一些设置对象IMMEMORY属性的具体用例, 摘录于此, 以备将来参考:

ALTER TABLESPACE ts_data INMEMORY;
ALTER TABLE sales INMEMORY NO INMEMORY(prod_id);
ALTER TABLE sales MODIFY PARTITION SALES_Q1_1998 NO INMEMORY;

此外,为了控制对象的装载顺序,Oracle定义了5种优先级来实现精细控制,通过priority子句来选择.详细信息如下:

根据自己的需求,可以选择以上几种优先级中的一种来定义该对象的装载顺序.若未指定priority子句,则其默认值为NONE.

IM对象的装载是由后台进程ora_w00*_完成的.参数inmemory_max_populate_servers控制IM后台装载进程的个数, 其默认值为cpu_count的一半. 进程数越多,装载速度越快,但消耗的资源也更多.

注:实际观察发现inmemory_max_populate_servers参数并不是对后台装载进程ora_w00*_的硬性限制,它更像是一个最小值的设定,因为实际中发现ora_w00*_进程数是可以动态增加的。

在对象载入In Memory区后, 可使用no inmemory操作将其从IM区清除

alter table TEST_IM no inmemory;

此外,要注意的是,改变原有的priority(或者memcompress)属性,也会导致该对象被清除出IM区.比如:

alter table TEST_IM inmemory priority critical;  --原值为none

这里还要注意的一点是,由于存储数据块的大小为1M的整数倍,也就是内存分配的最小单位是1M,为了避免空间浪费,Oracle不会将<=64K大小的对象载入In Memory区.这里做个简单测试来验证这一点:

create table test_im(v varchar2(100)) inmemory pctused 1 pctfree 99 tablespace users;
insert into test_im select rpad('a',100,'a') from dual connect by level <=5;
commit;
SQL> select bytes/1024 from dba_segments where segment_name='TEST_IM';
BYTES/1024
----------
        64
SQL> select * from TEST_IM;
…… 
SQL> select * from v$im_segments where segment_name='TEST_IM';
no rows selected

查询v$im_segments可发现表TEST_IM并不在IM区. 

SQL> insert into test_im select rpad('a',100,'a') from dual;
1 row created.
SQL> commit;
Commit complete.
SQL> select bytes/1024 from dba_segments where segment_name='TEST_IM';
BYTES/1024
----------
       128
SQL> select * from TEST_IM;
……
SQL> select SEGMENT_NAME,INMEMORY_SIZE,BYTES,POPULATE_STATUS from v$im_segments where segment_name='TEST_IM';
SEGMENT_NAME         INMEMORY_SIZE      BYTES POPULATE_STATUS
-------------------- ------------- ---------- --------------------
TEST_IM                    1179648     131072 COMPLETED

而当表TEST_IM的大小大于64K时,Oracle才会将其装载入In Memory区.

In Memory压缩

Oracle为IM中的对象提供了六种级别的压缩选项, 可通过MEMCOMPRESS子句来指定, 详细信息如下:

通过下例来观察In Memory列压缩功能:

SQL> create table test_im_comp tablespace users as select * from dba_objects;
Table created.
SQL> insert into test_im_comp select * from test_im_comp;
92203 rows created.
SQL> /
……
SQL> commit;
Commit complete.
SQL> alter table TEST_IM_COMP inmemory memcompress for query low;
SQL> select count(*) from test_im_comp;
  COUNT(*)
----------
   2950496

之后可以看到开始向In Memory区装载TEST_IM_COMP表:

select SEGMENT_NAME,INMEMORY_SIZE,BYTES,POPULATE_STATUS from v$im_segments;
SEGMENT_NAME                   INMEMORY_SIZE      BYTES POPULATE_
------------------------------ ------------- ---------- ---------
TEST_IM_COMP                         6553600  411041792 STARTED

等待一会, TEST_IM_COMP表装载完毕,从压缩前后的大小比对可看出,这里采用“memcompress for query low”压缩算法后TEST_IM_COMP表的压缩比大约为6:1。

SQL> select SEGMENT_NAME,INMEMORY_SIZE,BYTES,POPULATE_STATUS from v$im_segments;
 
SEGMENT_NAME                   INMEMORY_SIZE      BYTES POPULATE_
------------------------------ ------------- ---------- ---------
TEST_IM_COMP                        63373312  411041792 COMPLETED 

通过使用dbms_compression包,也可以预估数据库对象在采用不同压缩级别后载入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);
  comp_ratio_allrows NUMBER := -1;
BEGIN
  dbms_compression.get_compression_ratio (
  scratchtbsname => 'USERS',
  ownname => 'SYS',
  objname => 'TEST_IM_COMP',
  subobjname => NULL,
  comptype => dbms_compression.comp_inmemory_query_low,  --该参数控制压缩级别
  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('The IM compression ratio is '|| l_cmp_ratio);
END;
/
The IM compression ratio is 6

上述脚本中的comptype选项可从dbmscomp.sql脚本中获得,如下:

grep -i comp_inmemory $ORACLE_HOME/rdbms/admin/dbmscomp.sql
COMP_INMEMORY_NOCOMPRESS      CONSTANT NUMBER := 8192;
COMP_INMEMORY_DML             CONSTANT NUMBER := 16384;
COMP_INMEMORY_QUERY_LOW       CONSTANT NUMBER := 32768;
COMP_INMEMORY_QUERY_HIGH      CONSTANT NUMBER := 65536;
COMP_INMEMORY_CAPACITY_LOW    CONSTANT NUMBER := 131072;
COMP_INMEMORY_CAPACITY_HIGH   CONSTANT NUMBER := 262144;

在以上Oracle提供的5种压缩算法中,FOR QUERY LOW选项压缩后的数据查询性能最佳。它使用的是一些常规的压缩技术,如“Dictionary Encoding, Run Length Encoding and Bit-Packing”.

其他压缩技术的压缩比例更高,但随之带来的读取时解压成本也更高。 

In Memory区数据的访问

当访问In Memory区中的对象时,执行计划中会出现新的INMEMORY关键字:

--------------------------------------------------------------------------------------
| Id  | Operation                  | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |         |     6 |   312 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS INMEMORY FULL| TEST_IM |     6 |   312 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

但这里要注意的是, 当出现INMEMORY关键字时并不表示数据一定是在IM区获得的. 这里的INMEMORY只能说明TEST_IM表的INMEMORY属性已被enable,对该表数据的访问有可能是从IM区得到的.这里使用前面的例子来说明这一点:

create table test_im(v varchar2(100)) inmemory pctused 1 pctfree 99 tablespace users;
insert into test_im select rpad('a',100,'a') from dual connect by level <=5;
commit;
SQL> select bytes/1024 from dba_segments where segment_name='TEST_IM';
BYTES/1024
----------
        64
SQL> select * from TEST_IM;
…… 
SQL> select * from v$im_segments where segment_name='TEST_IM';
no rows selected
SQL> set autotrace traceonly
SQL> select * from test_im;
Elapsed: 00:00:00.03
Execution Plan
----------------------------------------------------------
Plan hash value: 2761107969
--------------------------------------------------------------------------------------
| Id  | Operation                  | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |         |     5 |   260 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS INMEMORY FULL| TEST_IM |     5 |   260 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          7  consistent gets
          0  physical reads
          0  redo size
        800  bytes sent via SQL*Net to client
        550  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          5  rows processed

这里可以看到,TEST_IM表并不在IM区,但执行计划显示得是TABLE ACCESS INMEMORY FULL,说明执行计划并不能作为判断是否是从IM区获取数据的依据.

随着IM功能的引入,Oracle增加了一些新的统计信息用于IM相关的统计,这里可以使用IM scan rows来统计IM访问的情况,继续上面的例子:

SQL> select name,value from v$mystat, v$statname where v$mystat.statistic# = v$statname.statistic# and v$statname.name = 'IM scan rows';
NAME                                                                  VALUE
---------------------------------------------------------------- ----------
IM scan rows                                                              6 
SQL> select * from test_im;
V
----------------------------------------------------------------------------------------------------
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
SQL> select name,value from v$mystat, v$statname where v$mystat.statistic# = v$statname.statistic# and v$statname.name = 'IM scan rows';
NAME                                                                  VALUE
---------------------------------------------------------------- ----------
IM scan rows                                                              6

IM scan rows统计值前后没有变化,可见这里的确没有IM访问.

SQL> insert into test_im select rpad('a',100,'a') from dual;
1 row created.
SQL> commit;
Commit complete.
SQL> select * from TEST_IM;
……
SQL> select SEGMENT_NAME,INMEMORY_SIZE,BYTES,POPULATE_STATUS from v$im_segments where segment_name='TEST_IM';
SEGMENT_NAME         INMEMORY_SIZE      BYTES POPULATE_STATUS
-------------------- ------------- ---------- --------------------
TEST_IM                    1179648     131072 COMPLETED 
SQL> set autotrace traceonly
SQL> select * from test_im;
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2761107969
--------------------------------------------------------------------------------------
| Id  | Operation                  | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |         |     6 |   312 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS INMEMORY FULL| TEST_IM |     6 |   312 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        805  bytes sent via SQL*Net to client
        550  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          6  rows processed
SQL> select name,value from v$mystat, v$statname where v$mystat.statistic# = v$statname.statistic# and v$statname.name = 'IM scan rows';
NAME                                                                  VALUE
---------------------------------------------------------------- ----------
IM scan rows                                                             12 

IM scan rows值增加了6, 说明这里的数据是从IM区获得的, 并且行数也完全吻合.

此外,观察autotrace的结果可发现,在使用了IM访问后,consistent gets也从之前的7降到了3。 

IMCU(In Memory Compression Units)

IMCU类似于表空间中extent的概念,是列数据在IM区中内存分配块的大小。后台进程ora_w00*在装载数据时,会分配自己的IMCU,并将分配给该进程的数据加载到该IMCU中。此后,当访问IM区中的列数据时,我们在统计信息中看到的consistent gets值也就是统计所访问IMCU的个数和所需访问metadata块的个数之和。特定对象所分配IMCU的详细信息,可从视图V_$IM_HEADER中查询。而其metadata块的信息可从视图V_$IM_SMU_CHUNK和V_$IM_SMU_HEAD查询。

在In Memory内部,以IMCU为单位,Oracle维护了一个In Memory Storage Index,记录IMCU单元中该列的最大值,最小值。此外,Oracle也会在metadata区为每个IMCU建立相应的metadata dictionary, metadata信息中会有一些列的统计信息。视图V_$IM_COL_CU可以帮助查询这些metadata dictionary信息。 

IM相关的视图:

SQL> SELECT VIEW_NAME FROM DBA_VIEWS WHERE VIEW_NAME LIKE 'V_$IM%';
VIEW_NAME
------------------------------------------------------------------------------------
V_$IM_SEGMENTS_DETAIL              --记录IM段对象的详细存储属性
V_$IM_SEGMENTS                     --记录IM段对象的存储属性
V_$IM_USER_SEGMENTS                         --记录当前用户下IM段对象的存储属性
V_$IM_TBS_EXT_MAP                  --记录IM1M子池对象的区间映射关系
V_$IM_SEG_EXT_MAP                  --记录IM区对象的所有区间映射关系
V_$IM_HEADER                       --记录IM区对象所分配IMCU的详细信息
V_$IM_COL_CU                       --记录IMCU中基于列的统计信息
V_$IM_SMU_HEAD
V_$IM_SMU_CHUNK
V_$IM_COLUMN_LEVEL                          --记录IMCU中对象的列级压缩属性,若未在列级定义,则改视图为空
10 rows selected.
--以上对各VIEW的注释来自测试中的观察,描述有可能欠准确。 

IM相关的等待事件:

SQL> select name from v$event_name where name like '%IM %';
NAME
----------------------------------------------------------------
IM buffer busy
enq: IM - contention for blr
IM CU busy
latch: IM area scb latch
latch: IM area sb latch
latch: IM seg hdr latch
latch: IM emb latch
enq: SY - IM populate by other session
IM populate completion
9 rows selected 

IM相关的统计信息:

SQL> select name from v$statname where name like 'IM %' order by 1;
NAME
----------------------------------------------------------------
IM fetches by rowid from IMCU
IM fetches by rowid from disk
IM fetches by rowid from fetch list
IM fetches by rowid from journal
IM fetches by rowid row invalid in IMCU
IM populate (faststart) CUs accumulated write time (ms)
IM populate (faststart) CUs bytes read
……
198 rows selected.

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/27243841/viewspace-1270723/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2013-05-14

  • 博文量
    17
  • 访问量
    273210