In-Memory Column Store DML 처리

IM Column Store에서의 DML 처리를 살펴보겠습니다.

Data Loads – 시나리오 1

첫번째 시나리오는 SALES1 테이블을 디폴트 priority로 생성하고 non-direct path data load 수행했을 때입니다.

[oracle@New-Features-12c ~]$ sqlplus labuser/labuser@pdb1

SQL*Plus: Release 12.1.0.2.0 Production on Fri Aug 28 11:36:05 2015

Copyright (c) 1982, 2014, Oracle. All rights reserved.

Last Successful login time: Fri Aug 28 2015 06:26:43 +00:00

Connected to:

Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 – 64bit Production

With the Partitioning, Oracle Label Security, OLAP, Advanced Analytics

and Real Application Testing options

SQL> create table sales1 as select * from sales where 1=2;

Table created.

SQL> alter table sales1 inmemory;

Table altered.

SQL> insert into sales1 select * from sales where rownum <= 10000;

10000 rows created.

SQL> commit;

Commit complete.

Commit을 했음에도 불구하고 v$im_segments를 통해 확인했을 때 SALES1 테이블이 아직 population 되지 않았습니다.

SQL> col segment_name for a20

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

no rows selected

IM transactions : Transactions issued by the session to In-Memory tables (i.e. the number of times COMMITs have been issued)

IM transactions rows journaled : Count of rows logged in the Transaction Journal by the session.

IM populate segments requested : The number of times the session has requested for In-Memory population of a segment.

세션 통계정보를 통해SALES1 테이블에 실행된 트랜젝션(IM transactions)은 1회이며 Transaction Journal에 기록된 로우 수(IM transactions rows journaled) 는 10000 이지만 해당 세그먼트에 대한 population 요청(IM populate segments requested)은 아직 없는 것을 알 수 있습니다.

SQL> set lines 120

SQL> col value for 999999999999999

SQL> select display_name, value

from v$mystat m, v$statname n

where m.statistic# = n.statistic#

and n.display_name in (

‘IM populate segments requested’ ,

‘IM transactions’ ,

‘IM transactions rows journaled’);

DISPLAY_NAME VALUE

—————————————————————- —————-

IM transactions 1

IM transactions rows journaled 10000

IM populate segments requested 0

DBMS_INMEMORY.POPULATE 프로시저를 이용해서 수동으로 SALES1 테이블을 populate 합니다. 프로시저 실행 후 population 상태를 딕셔너리뷰에서 확인합니다.

SQL> execute dbms_inmemory.populate(‘LABUSER’,’SALES1′,null);

PL/SQL procedure successfully completed.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 458752 1179648 0

Population 상세 상태를 확인합니다. SALES1 테이블에 대해 7개 익스텐트가 생성되어 있고 여기에는 56개 블록이 할당되어 있으나 50개 블록이 사용중(DATABLOCKS)임을 알 수 있습니다. 사용 중인 50개 블록 모두 IM Column Store에 population 되어 있습니다 (BLOCKSINMEM)

SQL> col object_name for a20

SQL> select a.object_name, b.membytes, b.extents, b.blocks,

b.datablocks, b.blocksinmem, b.bytes

from v$im_segments_detail b, dba_objects a

where a.data_object_id = b.dataobj

and a.object_name = ‘SALES1’;

OBJECT_NAME MEMBYTES EXTENTS BLOCKS DATABLOCKS BLOCKSINMEM BYTES

——————– ———- ———- ———- ———- ———– ———-

SALES1 1179648 7 56 50 50 458752

Data Loads – 시나리오 2

이번에는 Insert as Select 구문으로 SALES1 테이블에 추가 데이터를 입력해 보겠습니다.

“IM transactions” 이 commit으로 인해 기존 1에서 2로 증가하고, “IM transactions rows journaled” 값이 10000에서 10100으로 변경되는 것을 볼 수 있습니다.

SQL> insert into sales1 select * from sales where rownum <= 100;

100 rows created.

SQL> commit;

Commit complete.

SQL> select display_name, value

from v$mystat m, v$statname n

where m.statistic# = n.statistic#

and n.display_name in (

‘IM populate segments requested’ ,

‘IM transactions’ ,

‘IM transactions rows journaled’);

DISPLAY_NAME VALUE

—————————————————————- —————-

IM transactions 2

IM transactions rows journaled 10100

IM populate segments requested 1

세그먼트의 population 상태를 확인해 보면 소량의 데이터만을 추가로 입력했기 때문에(100건) 신규로 할당된 익스텐트나 블록은 없고, 이미 할당된 익스텐트 내에 데이터가 추가된 케이스라고 할 수 있습니다 (기존 값과 비교) 이는 trickle repopulation 대상입니다

SQL> select a.object_name, b.membytes, b.extents, b.blocks,

b.datablocks, b.blocksinmem, b.bytes

from v$im_segments_detail b, dba_objects a

where a.data_object_id = b.dataobj

and a.object_name = ‘SALES1’;

OBJECT_NAME MEMBYTES EXTENTS BLOCKS DATABLOCKS BLOCKSINMEM BYTES

——————– ———- ———- ———- ———- ———– ———-

SALES1 1179648 7 56 50 50 458752

v$im_segments에서 BYTES_NOT_POPULATED 수치가 0으로 나타나는 이유는 BYTES_NOT_POPULATED 가 세그먼트에 추가되었으나 아직 population 되지 않은 신규 익스텐트의 사이즈만을 나타내기 때문입니다.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 458752 1179648 0

추가된 로우의 population 정보는 v$im_header 뷰에서 관련 정보를 확인합니다. 현재 다음 같은 상태임을 알 수 있습니다. 하나의 IMCU 만 생성되어 있으며 (v$im_header에는 IMCU 1개당 1개 로우 생성) 7개 디스크 익스텐트, 50개 블록에 저장된 10100개의 로우가 매핑되어 있음 IMCU에 매핑되어 있습니다.

Tricke repopulation이 발생했음 (REPOPULATED 1, TRICKLE_REPOPULATED 1)

SQL> select b.object_name, a.prepopulated, a.repopulated,

a.trickle_repopulated, a.num_disk_extents, a.num_blocks,

a.num_rows, a.num_cols

from v$im_header a, dba_objects b

where a.objd = b.data_object_id

and b.object_name = ‘SALES1’;

OBJECT_NAME PREPOPULATED REPOPULATED TRICKLE_REPOPULATED NUM_DISK_EXTENTS NUM_BLOCKS NUM_ROWS NUM_COLS

——————– ———— ———– ——————- —————- ———- ———- ———-

SALES1 0 1 1 7 50 10100 7

Data Loads – 시나리오 3

이번에는 append 힌트를 사용하여 direct path insert를 해 보겠습니다. Repopulation이 필요한 새로운 extents 할당이 이루어진 것을 알 수 있습니다. 49 블록 (99-50) 이 IM Column Store에 아직 popuation 안되어 있습니다.

SQL> insert /*+ append */ into sales1 select * from sales where rownum <= 10000;

10000 rows created.

SQL> commit;

Commit complete.

SQL> select a.object_name, b.membytes, b.extents, b.blocks,

b.datablocks, b.blocksinmem, b.bytes

from v$im_segments_detail b, dba_objects a

where a.data_object_id = b.dataobj

and a.object_name = ‘SALES1’;

OBJECT_NAME MEMBYTES EXTENTS BLOCKS DATABLOCKS BLOCKSINMEM BYTES

——————– ———- ———- ———- ———- ———– ———-

SALES1 1179648 14 112 99 50 917504

v$im_segments의 BYTES_NOT_POPULATED 값은 SALES1 테이블이 완전히 population 되지 않았음을 보여주고 있습니다.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

2

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 917504 1179648 401408

수동으로 population을 합니다

force 옵션을 false로 하고 repopulate 프로시저를 수행한 후 population 상태를 확인해 보면 population이 아직 수행되지 않았음을 알 수 있습니다. 이는 force=>false 옵션이 IMCU 내 변경된 데이터만 (신규 IMCU가 아니라) population 시키는 옵션이기 때문입니다.

SQL> execute dbms_inmemory.repopulate(‘LABUSER’, ‘SALES1’, null, force=>false);

PL/SQL procedure successfully completed.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 917504 1179648 401408

false옵션을 true로 해서 수동으로 population 시킵니다. False=>true인 dbms_inmemory.repopulate 프로시저는 populate 프로시저와 동일하게 동작합니다. (population 되지 않은 디스크 익스텐트를 강제로 population 시킴)

SQL> execute dbms_inmemory.repopulate(‘LABUSER’, ‘SALES1’, null, force=>true);

PL/SQL procedure successfully completed.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 917504 1179648 0

Data Loads – 시나리오 4

이번에는 priority 속성을 high로 변경 후 direct path load 를 수행해 보겠습니다. 먼저 테이블 priority 변경 후, BYTES_NOT_POPULATED 이 0으로 population 완료 된 것을 확인합니다.

SQL> alter table sales1 inmemory priority high;

Table altered.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated from v$im_segments where segment_name =’SALES1′;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 917504 1179648 0

Direct path load로 데이터 입력 후 v$im_segments를 조회해 보면, 어느 정도 시간이 지난 후 (수초 ~ 1분) dbms_inmemory.repopulate 프로시저 실행이나 SALES1 테이블 조회와 같은 별도의 조치 없이도 population이 이루어 진 것을 확인할 수 있습니다.

SQL> insert /*+ append */ into sales1 select * from sales where rownum <= 10000;

10000 rows created.

SQL> commit;

Commit complete.

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated

from v$im_segments where segment_name = ‘SALES1’;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 2097152 1179648 401408

SQL> select segment_name, populate_status, bytes, inmemory_size, bytes_not_populated from v$im_segments where segment_name = ‘SALES1’;

SEGMENT_NAME POPULATE_ BYTES INMEMORY_SIZE BYTES_NOT_POPULATED

——————– ——— ———- ————- ——————-

SALES1 COMPLETED 2097152 1179648 0

By haisins

오라클 DBA 박용석 입니다. haisins@gmail.com 으로 문의 주세요.

One thought on “In-Memory Oracle 12c (대용량 배치편)”

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다