Oracle12c 新機能

update:

第3回「Oracle12c (12.1.0.2) In-Memory Option」

著者:吉田 宗弘

3.7 INMEMORY_CLAUSE_DEFAULT パラメータを指定した場合の動作

先にReference Manual でINMEMORY_CLAUSE_DEFAULT パラメータの説明に誤記がある旨記載しましたので、実際に確認してみましょう。

-- 先ずはManual に記載の通り、初期化パラメータファイルに以下の設定を行い、インスタンス
-- を再起動します。
-- INMEMORY_CLAUSE_DEFAULT='INMEMORY MEMCOMPRESS FOR QUERY LOW PRIORITY LOW'
SQL> show parameters clause
NAME                                 TYPE        VALUE
------------------------------------ ----------- -----------------------------------------------
inmemory_clause_default              string      INMEMORY MEMCOMPRESS FOR QUERY LOW PRIORITY LOW

-- 列を指定してIn-Memory 化した場合
SQL> drop table sales2 purge;
SQL> Create table Sales2 (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales2 primary key (id) using index tablespace users
) tablespace users
inmemory priority medium
inmemory memcompress for query high (storeid, salescnt)
no inmemory (txt);

SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales2;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..20 loop
insert into Sales2 select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/



SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESSION           CON_ID
---------- ------ --------------- ------------- -------------------------- ----------
SALES2                TABLE      USERS           38207488     213909504                   0
COMPLETED  MEDIUM AUTO            NO DUPLICATE  FOR QUERY LOW                       0
→ セグメント単位ではないので、このView のINMEMORY_COMPRESSION は無視

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896   38797312 DONE                0
64KB POOL      788529152     327680 DONE                0

SQL> select owner, table_name, column_name, inmemory_compression
from v$im_column_level;
OWNER      TABLE_NAME COLUMN_NAM INMEMORY_COMPRESSION
---------- ---------- ---------- --------------------------
SCOTT      SALES2     ID         DEFAULT
SCOTT      SALES2     STOREID    FOR QUERY HIGH
SCOTT      SALES2     ITEMID     DEFAULT
SCOTT      SALES2     SALESCNT   FOR QUERY HIGH
SCOTT      SALES2     TXT        NO INMEMORY
SCOTT      SALES2     SALESDATE  DEFAULT
→ NO INMEMORY 指定した列 (TXT) はNO INMEMORY のまま

-- セグメントを指定してIn-Memory 化した場合
SQL> drop table sales2 purge;
SQL> Create table Sales2 (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales2 primary key (id) using index tablespace users
) tablespace users
no inmemory;

SQL> declare
       ix   pls_integer;
       roff constant pls_integer := 100000;
       vtxt constant varchar2(64) := dbms_random.string('p', 64);
     begin
       select nvl(max(id),0) into ix from sales2;
       dbms_random.seed(to_char(systimestamp));
       for v1 in 1..20 loop
         insert into Sales2 select level + ix,
           trunc(dbms_random.value(1,100)),
           trunc(dbms_random.value(1000, 5000)),
           trunc(dbms_random.value(1, 10)),
           vtxt, sysdate - trunc(dbms_random.value(1, 100))
           from dual connect by level <= roff;
         ix := ix + roff;
         commit;
       end loop;
     end;
     /

SQL> select * from v$im_user_segments;
レコードが選択されませんでした。

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896    2097152 DONE                0
64KB POOL      788529152          0 DONE                0

SQL> select owner, table_name, column_name, inmemory_compression from v$im_column_level;
レコードが選択されませんでした。
→ IMC は使用されていない模様

SQL> select table_name, inmemory, inmemory_priority, inmemory_compression
from user_tables
where table_name = 'SALES2';
TABLE_NAME INMEMORY INMEMO INMEMORY_COMPRESSION
---------- -------- ------ --------------------------
SALES2     DISABLED

→ やはりDEFAULT の設定を変更しても、NO INMEMORY 指定されたものはIMC を使用しない。

 

Alter table 文又はCreate table 文でINMEMORY のみ指定して、優先レベルや圧縮属性を指定しなかった場合、INMEMORY_CLAUSE_DEFAULT パラメータの設定によって以下のように設定されます。
・INMEMORY_CLAUSE_DEFAULT パラメータが未設定の場合
システムのDefault である、Priority None, Memcompress for query low が設定されます。
・INMEMORY_CLAUSE_DEFAULT パラメータが設定されている場合
INMEMORY_CLAUSE_DEFAULT に指定されている値が設定されます。
それでは実際に、上記の動作を確認してみましょう。

-- INMEMORY_CLAUSE_DEFAULT の確認
SQL> show parameters clause
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_clause_default              string

-- テーブル作成/設定値確認
SQL> Create table tab1 (id number(8)) inmemory priority high memcompress for query high;
SQL> select table_name, inmemory, inmemory_priority, inmemory_compression
from user_tables where table_name = 'TAB1';
TABLE_NAME INMEMORY INMEMORY INMEMORY_COMPRESS
---------- -------- -------- -----------------
TAB1       ENABLED  HIGH     FOR QUERY HIGH
→ Create table で指定した値に設定されています。
-- 優先レベル, 圧縮属性を指定せずにinmemory の再設定/確認
SQL> alter table tab1 inmemory;
SQL> select table_name, inmemory, inmemory_priority, inmemory_compression
from user_tables where table_name = 'TAB1';
TABLE_NAME INMEMORY INMEMORY INMEMORY_COMPRESS
---------- -------- -------- -----------------
TAB1       ENABLED  NONE     FOR QUERY LOW
→ システムのDefault であるPriority None, Memcompress for query low に変更されています。

-- inmemory_clause_default の変更/確認
SQL> alter system set inmemory_clause_default= 'INMEMORY MEMCOMPRESS FOR DML PRIORITY LOW';
SQL> show parameters clause
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------------------
inmemory_clause_default              string       INMEMORY MEMCOMPRESS FOR DML PRIORITY LOW

-- 優先レベル, 圧縮属性を指定せずにinmemory の再設定/確認
SQL> alter table tab1 inmemory;
SQL> select table_name, inmemory, inmemory_priority, inmemory_compression
from user_tables where table_name = 'TAB1';
TABLE_NAME INMEMORY INMEMORY INMEMORY_COMPRESS
---------- -------- -------- -----------------
TAB1       ENABLED  LOW      FOR DML
→ inmemory_clause_default の値に設定値が上書きされました。


3.8 表領域にIn-Memory Option のDefault 値を設定した場合

これまでTable 作成時に直接In-Memory Option のパラメータを指定してきましたが、予め表領域にDefault のIn-Memory Option を設定しておき、該当の表領域にTable が作成された時にDefault 値を反映させる事も可能です。但し既存のテーブルを該当表領域に移動しても、表領域のDefault に設定したIn-Memory 属性は強制されません。
それでは実際に、確認してみましょう。

-- In-Memory 属性を指定した表領域の作成/確認
-- 非RAC 環境の場合、表領域のDefault 句に指定できるのは、圧縮指定とPriority のみ
SQL> Create tablespace imtbs1 datafile '/add_disk2/oradata/ora121/imtbs1.dbf'
  size 1024m autoextend off
       default inmemory memcompress for query high priority high;
SQL> select tablespace_name, def_inmemory, def_inmemory_priority, def_inmemory_compression
       from dba_tablespaces
       where tablespace_name = 'IMTBS1';
TABLESPACE_NAME DEF_INME DEF_INME DEF_INMEMORY_COMP
--------------- -------- -------- -----------------
IMTBS1          ENABLED  HIGH     FOR QUERY HIGH

-- In-Memory 属性を指定した表領域にテーブル作成/データセット
SQL> drop table Sales2 purge;
SQL> Create table Sales2 (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales2 primary key (id) using index tablespace imtbs1
) tablespace imtbs1;
SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales2;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..50 loop
insert into Sales2 select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/



-- データ投入中に別セッションから状態を確認
SQL> select * from v$im_user_segments;
レコードが選択されませんでした。
SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896    2097152 POPULATING          0
64KB POOL      788529152    5505024 POPULATING          0
→ データを投入するだけで、IMC への移入が開始されている。

-- 数分後 (データ投入中) に再度状態を確認
SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES2                TABLE      IMTBS1           5439488     335544320           283910144
STARTED    HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             0
SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896    7340032 POPULATING          0
64KB POOL      788529152    4390912 POPULATING          0

-- Insert 完了後
SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES2                TABLE      IMTBS1          27721728     536870912           309166080
STARTED    HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             0
SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896   29360128 POPULATING          0
64KB POOL      788529152     458752 POPULATING          0

-- 移入完了後
SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES2                TABLE      IMTBS1          66977792     536870912                   0
COMPLETED  HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             0

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896   68157440 DONE                0
64KB POOL      788529152     917504 DONE                0



-- 既存のテーブルを該当表領域に移動した際の動作を確認
-- In-Memory 属性を指定せず、Table 再作成
SQL> drop table Sales2 purge;
SQL> Create table Sales2 (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales2 primary key (id) using index tablespace users
) tablespace users;
SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales2;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..50 loop
insert into Sales2 select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/

-- データ投入完了後、状態を確認
SQL> select * from v$im_user_segments;
レコードが選択されませんでした。

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896    2097152 DONE                0
64KB POOL      788529152          0 DONE                0

SQL> select table_name, tablespace_name, inmemory, inmemory_priority, inmemory_compression
from user_tables
where table_name = 'SALES2';
TABLE_NAME      TABLESPACE INMEMORY INMEMO INMEMORY_COMPRESS
--------------- ---------- -------- ------ -----------------
SALES2          USERS      DISABLED



-- Table をIn-Memory 属性を指定した表領域に移動/状態確認
SQL> alter table sales2 move tablespace IMTBS1;
SQL> select table_name, tablespace_name, inmemory, inmemory_priority, inmemory_compression
from user_tables
where table_name = 'SALES2';
TABLE_NAME      TABLESPACE INMEMORY INMEMO INMEMORY_COMPRESS
--------------- ---------- -------- ------ -----------------
SALES2          IMTBS1     DISABLED
→  表領域は移動しましたが、INMEMORY はDISABLE のままです。
該当の表領域に作成された訳ではないため、既存の設定が優先されています。

-- 一旦表領域を戻して、再度表領域の移動とIn-Memory 属性の指定を同時に行ってみます。
SQL> alter table sales2 move tablespace users;
SQL> alter table sales2 move tablespace imtbs1 inmemory priority low;
SQL> select table_name, tablespace_name, inmemory, inmemory_priority, inmemory_compression
from user_tables
where table_name = 'SALES2';
TABLE_NAME      TABLESPACE INMEMORY INMEMO INMEMORY_COMPRESS
--------------- ---------- -------- ------ -----------------
SALES2          IMTBS1     ENABLED  LOW    FOR QUERY LOW
→  表領域は移動して、Alter table 文で指定したIn-Memory 属性 (優先度) が設定されました。
圧縮属性については表領域のDefault ではなく、システムのDefault が設定されています。

-- 移入状況確認
SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES2                TABLE      IMTBS1          95092736     545259520                   0
COMPLETED  LOW    AUTO            NO DUPLICATE  FOR QUERY LOW              0

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL      3220176896   96468992 DONE                0
64KB POOL      788529152     720896 DONE                0
→ IMC への移入も行われました。

-- Table の表領域を移動したので、索引のRebuild
SQL> select index_name, status from user_indexes where status != 'VALID';
INDEX_NAME      STATUS
--------------- ----------
PK_SALES2       UNUSABLE

SQL> alter index pk_sales2 rebuild;
SQL> select index_name, status from user_indexes where status != 'VALID';
レコードが選択されませんでした。


3.9 Multitenant Architecture との併用

前節までは非Multitenant Architecture 環境でIn-Memory Option の動作確認を行ってきました。In-Memory Option はOracle 12c のもう一つの目玉機能であるMultitenant Architecture との併用が可能です。Multitenant Architecture と併用した場合、In-Memory Option の動作は以下のようになります。

[Multitenant Architecture 環境下でのIn-Memory Option の動作]
・メモリ領域 (IMC), プロセス等は全てCDB が持つ
・INMEMORY_SIZE パラメータは、CDB/各PDB で指定可能
・IMC はCDB のINMEMORY_SIZE パラメータで指定されたサイズで作成される。
・各PDB は、PDB毎のINMEMORY_SIZE で指定したサイズまで、IMC を使用できる。
PDBのINMEMORY_SIZE パラメータを0 に設定すると、該当のPDB ではIMC が使用不可になる。
・各PDB のINMEMORY_SIZE の合計がCDB のINMEMORY_SIZE を超えても構わない。

それでは実際に確認してみましょう。

-- Multitenant Architecture 環境の準備
-- 以下のMultitenant Architecture 環境 を作成しました。
$ sqlplus "/ as sysdba"
SQL> show pdbs
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 PDB01                          READ WRITE NO
         4 PDB02                          READ WRITE NO
         5 PDB03                          READ WRITE NO
PDB01 ~ PDB03 の各PDB には、以下の設定を行っています。
・USERS 表領域の作成
・DBA 権限を持った scott ユーザの作成

-- 接続先の確認
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT                       ← Container Database に接続中

-- Container DB のINMEMORY_SIZE パラメータの設定
SQL> alter system set inmemory_size=1024M scope=spfile;
-- 一旦インスタンスを再起動して、CDB の設定を反映させる。
SQL> shutdown immediate
SQL> startup
SQL> alter pluggable database all open read write;
SQL> show pdbs
CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED                       READ ONLY  NO
3 PDB01                          READ WRITE NO
4 PDB02                          READ WRITE NO
5 PDB03                          READ WRITE NO


-- 各PDB に接続してinmemory_size パラメータを設定
-- PDB では、CDBのinmemory_size 以下の範囲で動的にinmemory_size を変更できる
-- CDB で指定するinmemory_size パラメータは64KB Pool の領域を含んだサイズだが、
-- PDB で指定するinmemory_size パラメータは1MB Pool のサイズとなる。
-- PDB の inmemory_size パラメータには、CDB の1MB Pool サイズを超える値を指定可能だが
-- CDB の1MB Pool のサイズを超えてIMC を使用する事はできない。

SQL> alter session set container=pdb$seed;
SQL> alter system set inmemory_size=0;
SQL> alter session set container=pdb01;
SQL> alter system set inmemory_size=640M;
SQL> alter session set container=pdb02;
SQL> alter system set inmemory_size=640M;
-- CDB のInmemory_size を超える値は設定できない
SQL> alter session set container=pdb03;
SQL> alter system set inmemory_size=1100M;
ORA-02097: 指定した値が無効なので、パラメータを変更できません。 ORA-02095:
指定した初期化パラメータを変更できません。
SQL> alter system set inmemory_size=0;

CDB/各PDB に設定されているパラメータを確認
SQL> alter session set container=cdb$root;
SQL> select con_id, name, value from v$system_parameter where name='inmemory_size';
CON_ID NAME                 VALUE
---------- -------------------- --------------------
0 inmemory_size        1073741824       ← DB全体に対しての設定
2 inmemory_size        0                ← PDB$SEED に対しての設定
3 inmemory_size        671088640        ← PDB01 に対しての設定
4 inmemory_size        671088640        ← PDB02 に対しての設定
5 inmemory_size        0                ← PDB03 に対しての設定

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
------------ ----------- ---------- --------------- ----------
1MB POOL       854589440          0 DONE                     1  ←CDB$ROOT への割当て
64KB POOL      201326592          0 DONE                     1
1MB POOL       854589440          0 DONE                     2  ←PDB$SEED への割当て
64KB POOL      201326592          0 DONE                     2
1MB POOL       854589440          0 DONE                     3  ←PDB01 への割当て
64KB POOL      201326592          0 DONE                     3
1MB POOL       854589440          0 DONE                     4  ←PDB02 への割当て
64KB POOL      201326592          0 DONE                     4
1MB POOL       854589440          0 DONE                     5  ←PDB03 への割当て
64KB POOL      201326592          0 DONE                     5
→ 見かけ上、全てのDB に1024MB のIMU が割り当てられているように見えます。


-- PDB にテーブルを作成してIn-Memory 化してみる。
SQL> connect scott/tiger@pdb01
SQL> show con_name
CON_NAME
------------------------------
PDB01

SQL> Create table Sales (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales primary key (id) using index tablespace users
) tablespace users;
SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..50 loop
insert into Sales select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/
SQL> alter table sales inmemory priority high
memcompress for query high;

SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_STATUS INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
--------------- ------ --------------- ------------- ----------------- ----------
SALES                 TABLE      USERS           66781184     536870912                   0
COMPLETED       HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             3

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_STATUS     CON_ID
------------ ----------- ---------- --------------- ----------
1MB POOL       854589440   66060288 DONE                     3

64KB POOL      201326592     720896 DONE                     3

-- Container DB から状態を確認
SQL> conn / as sysdba
SQL> select *  from v$im_segments;
OWNER      SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES
---------- ---------- ---------- ---------- ---------- ------------- -------------
BYTES_NOT_POPULATED POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
------------------- ---------- ------ --------------- ------------- ----------------- ----------
SCOTT      SALES                 TABLE      USERS           66781184     536870912
                  0 COMPLETED  HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             3

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL       854589440   66060288 DONE                1
64KB POOL      201326592     720896 DONE                1
1MB POOL       854589440   66060288 DONE                2
64KB POOL      201326592     720896 DONE                2
1MB POOL       854589440   66060288 DONE                3
64KB POOL      201326592     720896 DONE                3
1MB POOL       854589440   66060288 DONE                4
64KB POOL      201326592     720896 DONE                4
1MB POOL       854589440   66060288 DONE                5
64KB POOL      201326592     720896 DONE                5

→ v$im_segments からはCON_ID 列でどのPDB がIMC を使用しているか分かるが
v$inmemory_area からは分からない。

別のPDB (PDB02) でもやってみる。
SQL> connect scott/tiger@pdb02
SQL> show con_name
CON_NAME
------------------------------
PDB02

SQL> select * from v$im_user_segments;
レコードが選択されませんでした。

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL       854589440   66060288 DONE                4
64KB POOL      201326592     720896 DONE                4


SQL> Create table Sales (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales primary key (id) using index tablespace users
) tablespace users;
SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..70 loop
insert into Sales select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/

SQL> alter table sales inmemory priority high no memcompress;

SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES                 TABLE      USERS          633339904     754974720            42254336
COMPLETED  HIGH   AUTO            NO DUPLICATE  NO MEMCOMPRESS             4

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL       854589440  722468864 DONE                4
64KB POOL      201326592    3866624 DONE                4

-- PDB02 に設定したinmemory_size に達したため、bytes_not_populated が0になる前に
-- Populate が完了している。
-- 但し、1MB Pool を使い切った訳では無いので、v$inmemory_area のPopulate_status も
-- Out of Memory にはなっていない
-- alert log には、以下の警告が出ている。
-- Insufficient memory to populate table to inmemory area


-- 再度Container DB から確認
SQL> conn / as sysdba
SQL> select * from v$im_segments;
OWNER      SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES
---------- ---------- ---------- ---------- ---------- ------------- -------------
BYTES_NOT_POPULATED POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
------------------- ---------- ------ --------------- ------------- ----------------- ----------
SCOTT      SALES                 TABLE      USERS           66781184     536870912
0 COMPLETED  HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             3

SCOTT      SALES                 TABLE      USERS          633339904     754974720
42254336 COMPLETED  HIGH   AUTO            NO DUPLICATE  NO MEMCOMPRESS             4

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL       854589440  722468864 DONE                1
64KB POOL      201326592    3866624 DONE                1
1MB POOL       854589440  722468864 DONE                2
64KB POOL      201326592    3866624 DONE                2
1MB POOL       854589440  722468864 DONE                3
64KB POOL      201326592    3866624 DONE                3
1MB POOL       854589440  722468864 DONE                4
64KB POOL      201326592    3866624 DONE                4
1MB POOL       854589440  722468864 DONE                5
64KB POOL      201326592    3866624 DONE                5

-- PDB02 はPDB に設定したInmemory_size に達してしまったが、PDB01 はまだ余裕があるので
-- 追加のテーブルを作成してIn-Memory 化してみる。
SQL> conn scott/tiger@pdb01

SQL> select * from v$inmemory_area;
POOL         ALLOC_BYTES USED_BYTES POPULATE_S     CON_ID
------------ ----------- ---------- ---------- ----------
1MB POOL       854589440  722468864 DONE                3
64KB POOL      201326592    3866624 DONE                3

SQL> Create table Sales2 (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk2_sales primary key (id) using index tablespace users
) tablespace users;



SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales2;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..50 loop
insert into Sales2 select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/

SQL> alter table sales2 inmemory priority high
memcompress for capacity high;
SQL> select * from v$im_user_segments;
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES2                TABLE      USERS            1245184     536870912           516169728
STARTED    HIGH   AUTO            NO DUPLICATE  FOR CAPACITY HIGH          3

SALES                 TABLE      USERS           66781184     536870912                   0
COMPLETED  HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             3

SQL> /
SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES BYTES_NOT_POPULATED
---------- ---------- ---------- ---------- ------------- ------------- -------------------
POPULATE_S INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS     CON_ID
---------- ------ --------------- ------------- ----------------- ----------
SALES2                TABLE      USERS           39518208     536870912                   0
COMPLETED  HIGH   AUTO            NO DUPLICATE  FOR CAPACITY HIGH          3

SALES                 TABLE      USERS           66781184     536870912                   0
COMPLETED  HIGH   AUTO            NO DUPLICATE  FOR QUERY HIGH             3
--> PDB01 はOk


-- PDB03 は、inmemory_size=0 の設定なので、IMCは使用されない。
SQL> connect scott/tiger@pdb03
SQL> show con_name
CON_NAME
------------------------------
PDB03
SQL> show parameters inmemory_size
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
inmemory_size                        big integer 0

SQL> Create table Sales (
id         number(12),
StoreID    number(4),
ItemID     number(8),
SalesCnt   number(6),
txt        varchar2(64),
SalesDate  date,
constraint pk_sales primary key (id) using index tablespace users
) tablespace users;
SQL> declare
ix   pls_integer;
roff constant pls_integer := 100000;
vtxt constant varchar2(64) := dbms_random.string('p', 64);
begin
select nvl(max(id),0) into ix from sales;
dbms_random.seed(to_char(systimestamp));
for v1 in 1..10 loop
insert into Sales select level + ix,
trunc(dbms_random.value(1,100)),
trunc(dbms_random.value(1000, 5000)),
trunc(dbms_random.value(1, 10)),
vtxt, sysdate - trunc(dbms_random.value(1, 100))
from dual connect by level <= roff;
ix := ix + roff;
commit;
end loop;
end;
/

SQL> alter table sales inmemory priority high
memcompress for capacity high;

-- 10分待機
SQL> select * from v$im_user_segments;
レコードが選択されませんでした。
--> システム全体としてIn-Memory は有効化されているので、Alter table 文は成功するが、

    PDB03はInmemory_size が0 となっているためIn-Memory 化は行われません。

以上でCDB に割当てられたIMC を、複数のPDB がPDB 毎の利用制限に従って利用できる事が確認できました。それでは最後に、PDB がCDB に割当てられたIMCを使い切ってしまった場合の動作を確認してみましょう。

SQL> connect / as sysdba
SQL> select con_id, owner, table_name from cdb_tables where inmemory = 'ENABLED';
CON_ID OWNER      TABLE_NAME
------ ---------- ----------
     3 SCOTT      SALES2
     3 SCOTT      SALES
     4 SCOTT      SALES
     5 SCOTT      SALES

SQL> connect scott/tiger@pdb01
SQL> alter table sales no inmemory;
SQL> SQL> alter table sales2 no inmemory;
SQL> connect scott/tiger@pdb02
SQL> alter table sales no inmemory;
SQL> connect scott/tiger@pdb03
SQL> alter table sales no inmemory;
-- PDB03 でIMC が使用できるよう設定
SQL> alter system set inmemory_size = 512m;
SQL> connect / as sysdba
SQL> select con_id, owner, table_name from cdb_tables where inmemory = 'ENABLED';
レコードが選択されませんでした。

SQL> select con_id, name, value from v$system_parameter where name='inmemory_size';
CON_ID NAME                 VALUE
------ -------------------- --------------------
0 inmemory_size        1073741824
2 inmemory_size        0
3 inmemory_size        671088640
4 inmemory_size        671088640
5 inmemory_size        536870912

SQL> select * from v$im_segments;
レコードが選択されませんでした

SQL> connect scott/tiger@pdb01
SQL> alter table sales inmemory priority low no memcompress;
SQL> connect scott/tiger@pdb02
SQL> alter table sales inmemory priority low no memcompress;
SQL> connect / as sysdba
SQL> select * from v$im_segments;
OWNER      SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES
---------- ---------- ---------- ---------- ---------- ------------- -------------
BYTES_NOT_POPULATED POPULATE_STATUS INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS CON_ID
------------------- --------------- ------ --------------- ------------- ----------------- ------
SCOTT      SALES                 TABLE      USERS          426967040     536870912
56705024 STARTED         LOW    AUTO            NO DUPLICATE  NO MEMCOMPRESS         3



SQL> select * from v$im_segments;
POOL       ALLOC_BYTES USED_BYTES POPULATE_STATUS CON_ID
---------- ----------- ---------- --------------- ------
1MB POOL     854589440  441450496 POPULATING           1
64KB POOL    201326592    2293760 POPULATING           1
1MB POOL     854589440  441450496 DONE                 2
64KB POOL    201326592    2293760 DONE                 2
1MB POOL     854589440  441450496 POPULATING           3
64KB POOL    201326592    2293760 POPULATING           3
1MB POOL     854589440  441450496 POPULATING           4
64KB POOL    201326592    2293760 POPULATING           4
1MB POOL     854589440  441450496 POPULATING           5
64KB POOL    201326592    2293760 POPULATING           5

SQL> select * from v$im_segments;
OWNER      SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES
---------- ---------- ---------- ---------- ---------- ------------- -------------
BYTES_NOT_POPULATED POPULATE_STATUS INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS CON_ID
------------------- --------------- ------ --------------- ------------- ----------------- ------
SCOTT      SALES                 TABLE      USERS          476446720     536870912
0 COMPLETED       LOW    AUTO            NO DUPLICATE  NO MEMCOMPRESS         3

SCOTT      SALES                 TABLE      USERS          354091008     754974720
345907200 COMPLETED       LOW    AUTO            NO DUPLICATE  NO MEMCOMPRESS         4

SQL> select * from v$inmemory_area;
POOL       ALLOC_BYTES USED_BYTES POPULATE_STATUS CON_ID
---------- ----------- ---------- --------------- ------
1MB POOL     854589440  854589440 OUT OF MEMORY        1
64KB POOL    201326592    4259840 DONE                 1
1MB POOL     854589440  854589440 OUT OF MEMORY        2
64KB POOL    201326592    4259840 DONE                 2
1MB POOL     854589440  854589440 OUT OF MEMORY        3
64KB POOL    201326592    4259840 DONE                 3
1MB POOL     854589440  854589440 OUT OF MEMORY         4
64KB POOL    201326592    4259840 DONE                 4
1MB POOL     854589440  854589440 OUT OF MEMORY         5
64KB POOL    201326592    4259840 DONE                 5
→ IMC の1MB POOL を使い切りました。

SQL> connect scott/tiger@pdb03
SQL> alter table sales inmemory priority high
memcompress for query high;
-- 10分待機
SQL> select * from v$im_segments;
レコードが選択されませんでした。

→ IMC を使い切っているため、後からIn Memory 指定したTable はIn-Memory 化されていません。

-- In-Memory 化できなかったTable にアクセスしてみる。
SQL> select min(salesdate), max(salesdate), count(*) from sales where storeid=10;
MIN(SALE MAX(SALE   COUNT(*)
-------- -------- ----------
15-01-01 15-04-09       9966

SQL> select min(salesdate), max(salesdate), count(*) from sales where storeid=25;
MIN(SALE MAX(SALE   COUNT(*)
-------- -------- ----------
15-01-01 15-04-09      10048

-- 再度IMC の状態を確認
SQL> select * from v$im_segments;
レコードが選択されませんでした。

-- Container DB からも確認してみる
SQL> connect / as sysdba
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT

SQL> select * from v$im_segments;
OWNER      SEGMENT_NA PARTITION_ SEGMENT_TY TABLESPACE INMEMORY_SIZE         BYTES
---------- ---------- ---------- ---------- ---------- ------------- -------------
BYTES_NOT_POPULATED POPULATE_STATUS INMEMO INMEMORY_DISTRI INMEMORY_DUPL INMEMORY_COMPRESS CON_ID
------------------- --------------- ------ --------------- ------------- ----------------- ------
SCOTT      SALES                 TABLE      USERS          476446720     536870912
0 COMPLETED       LOW    AUTO            NO DUPLICATE  NO MEMCOMPRESS         3

SCOTT      SALES                 TABLE      USERS          354091008     754974720

          345907200 COMPLETED       LOW    AUTO            NO DUPLICATE  NO MEMCOMPRESS         4

[ご参考] CDB/PDB の接続で使用した、tnsnames.ora/listener.ora
Multitenant Architecture では、tnsnames.ora にSERVICE_NAME にPDB名を指定した接続文字列に指定する事で、任意のPDB に接続する事ができます。ここでは、ご参考までに本検証で使用したtnsnames.ora, listener.ora を記載します。
※ ora12102 はDB Server のホスト名です。

$ cd $ORACLE_HOME/network/admin
$ cat tnsnames.ora

# Container DB への接続文字列
cdb =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora12102)(PORT = 1521))
(CONNECT_DATA = (SID = ora121))
)

# Pluggable DB (PDB01) への接続文字列
pdb01 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora12102)(PORT = 1521))
(CONNECT_DATA = (SERVICE_NAME = pdb01))
)

# Pluggable DB (PDB02) への接続文字列
pdb02 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora12102)(PORT = 1521))
(CONNECT_DATA = (SERVICE_NAME = pdb02))
)

# Pluggable DB (PDB03) への接続文字列
pdb03 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora12102)(PORT = 1521))
(CONNECT_DATA = (SERVICE_NAME = pdb03))
)

$ cat listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora12102)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)

 

4. まとめ

以上でIn-Memory Option について一通りの確認ができました。In-Memory Option を使用すると、DWH 系の処理を大幅に高速化する事ができます。更に、DWH 用に定義されていた索引が不要になるため、OLTP 系の処理性能向上も期待できます。またIMCU はBuffer Cache との一貫性が保障されているため、常に最新のデータで分析処理を行わせる事が可能です。しかし稀に、最新データではなく静止点を決めて分析処理を行わせたい場合もあるでしょう。そのような場合は、Materialized View を対象にして分析処理を行う事で、同じDatabase 内に静止点を作成する事も可能です。In-Memory Option を使用する事で、基幹系のシステムとDWH 系のシステムを1つのDatabase に集約できる可能性も出てきました。更にIn-Memory Option は、Oracle 12c のDatabase 集約機能であるMultitenant Architecture との併用も可能ですので、Database の集約効率の更なる向上も期待できます。
今回見てきた通り、In-Memory Option の導入は非常に簡単ですが、導入効果は非常に大きいと言えます。性能が出ないDWH アプリケーションでお悩みの方は、一度In-Memory Option を試してみては如何でしょうか?



参考情報

In-Memory Option の概要
http://www.oracle.com/technetwork/jp/database/in-memory/overview/index.html
http://www.oracle.com/technetwork/jp/database/articles/pickup/database-in-memory-2283690-ja.html

In-Memory Option ホワイト・ペーパー
http://www.oracle.com/technetwork/jp/database/in-memory/overview/twp-oracle-database-in-memory-2245633-ja.pdf

Oracle 12.1.0.2 Core Tech セミナー
http://www.oracle.com/technetwork/jp/ondemand/od12c-coretech-aug2014-2283256-ja.html
http://www.oracle.com/webfolder/technetwork/jp/ondemand/od12c-aug2014/09-DB12102-coretech-DBIM-population-v1.pdf

Oracle 12.1.0.2 新機能概要
https://blogs.oracle.com/otnjp/entry/database_12c_new_feature

Oracle 12.1.0.2 管理者ガイド
https://docs.oracle.com/cd/E57425_01/121/ADMIN/memory.htm#BABHGBGE

Oracle 12.1.0.2 Database SQL 言語リファレンス
http://docs.oracle.com/cd/E57425_01/121/SQLRF/toc.htm

Oracle 12.1.0.2 Database リファレンス
http://docs.oracle.com/cd/E57425_01/121/REFRN/toc.htm

Oracle 12.1.0.2 Database PL/SQL パッケージおよびタイプ・リファレンス
http://docs.oracle.com/cd/E57425_01/121/ARPLS/toc.htm