본문 바로가기

Database/Oracle Database

처음 사용자를 위한 Oracle Database In-Memory 사용 가이드 - #6. 참고. 칼럼 레벨 In-Memory 설정 및 In-Memory hybrid scan

"처음 사용자를 위한 Oracle Database In-Memory 가이드" 시리즈를 통해 Swingbench의 분석 업무 스키마 ‘SH’ 데이터를 이용해서 오라클 21c Single 인스턴스 데이터베이스와 RAC 데이터베이스에서 간단한 In-memory 옵션 사용 방법을 살펴봅니다.

 

글 순서

#1. Introduction

#2. 테스트 환경 준비

#3. In-Memory Advisor

#4. In-Memory 테스트 – Single 인스턴스 DB: In-Memory 설정 & Population

#5. In-Memory 테스트 – Single 인스턴스 DB: In-Memory 수행 확인

#6. 참고. 칼럼 레벨 In-Memory 설정 및 In-Memory hybrid scan

#7. 참고. IM FastStart 수행 확인

#8. In-Memory 테스트 – RAC DB: In-Memory 설정 & Population

#9. In-Memory 테스트 – RAC DB: In-Memory 수행 확인

#10. In-Memory 테스트 – RAC DB: Auto DOP 적용 테스트

#11. In-Memory 테스트 – RAC DB: Distribute For Service 테스트

 

In-Memory Hybrid Scan

디폴트로 INMEMORY 속성 테이블의 모든 칼럼은 IM Column Store에 저장되지만, 메모리 크기 제약 등의 이유 등으로 테이블 내 개별 칼럼 레벨에서 INMEMORY 구문을 사용할 수도 있다. 각 칼럼 별로 다른 In-Memory압축 레벨을 사용할 수도 있다.  External 테이블은 칼럼 레벨 In-Memory 설정을 지원하지 않는다.

In-Memory hybrid scan은 모든 칼럼이 population 되어 있지 않은 IM Column Store 테이블에 엑세스할 때 사용되는 옵티마이저의 기법이다. 오라클 데이터베이스21c 이전에는 NO INMEMORY 설정이 있는 칼럼을 참조하는 경우, 해당 쿼리는 로우 스토어에서 모든 데이터를 엑세스했었다. 따라서 칼럼 포맷, Predicate pushdown과 같은 In-Memory 기능의 잇점을 얻지 못했다. 오라클 데이터베이스21c 부터는 INMEMORY와 NO INMEMORY 칼럼 참조하는 쿼리도 아래 조건에 만족하는 경우, 칼럼 포맷 데이터에 엑세스할 수 있게 되었다.

  • Predicate에는 INMEMORY 칼럼만 포함
  • SELECT 절에는 INMEMORY, NO INMEMORY 둘 다 포함 가능

In-Memory hybrid scan은 수행 여부는 실행 계획을 통해 알 수 있다.

In-Memory hybrid scan 확인하기 위해 우선 테스트 테이블을 만들고, 테이블은 INMEMORY 속성으로, 소속 칼럼 일부는 IMMEMORY MEMCOMPRESS FOR QUERY 옵션으로, 일부는 INMEMORY MEMCOMPRESS FOR CAPACITY HIGH 옵션으로 압축했다. 그리고 나머지 칼럼은 NO INMEMORY 옵션을 부여했다.

SQL> show con_name
CON_NAME
------------------------------
DB0621_PDB1
 
SQL> create table sh.sales_colim as select * from sh.sales;
Table created.
 
SQL> alter table sh.sales_colim inmemory;
Table altered.
 
SQL> alter table sh.sales_colim
   inmemory memcompress for query (
      prod_id, cust_id, time_id, channel_id, promo_id, quantity_sold)
   INMEMORY MEMCOMPRESS FOR CAPACITY HIGH (
      seller, fulfillment_center, courier_org, amount_sold)
   no inmemory (
      tax_country, tax_region);
Table altered.
 
SQL> col segment_name for a30
SQL> select segment_name, inmemory, inmemory_compression from dba_segments where owner ='SH' and segment_name='SALES_COLIM';
SEGMENT_NAME                   INMEMORY INMEMORY_COMPRESS
------------------------------ -------- -----------------
SALES_COLIM                    ENABLED  FOR QUERY LOW
 
SQL> set pages 100
SQL> col table_name for a20
SQL> col column_name for a35
SQL> select table_name, column_name, inmemory_compression from v$im_column_level where table_name = 'SALES_COLIM';
TABLE_NAME           COLUMN_NAME                         INMEMORY_COMPRESSION
-------------------- ----------------------------------- --------------------------
SALES_COLIM          PROD_ID                             FOR QUERY LOW
SALES_COLIM          CUST_ID                             FOR QUERY LOW
SALES_COLIM          TIME_ID                             FOR QUERY LOW
SALES_COLIM          CHANNEL_ID                          FOR QUERY LOW
SALES_COLIM          PROMO_ID                            FOR QUERY LOW
SALES_COLIM          QUANTITY_SOLD                       FOR QUERY LOW
SALES_COLIM          SELLER                              FOR CAPACITY HIGH
SALES_COLIM          FULFILLMENT_CENTER                  FOR CAPACITY HIGH
SALES_COLIM          COURIER_ORG                         FOR CAPACITY HIGH
SALES_COLIM          TAX_COUNTRY                         NO INMEMORY
SALES_COLIM          TAX_REGION                          NO INMEMORY
SALES_COLIM          AMOUNT_SOLD                         FOR CAPACITY HIGH
 
12 rows selected.

 

테스트 테이블의 In-Memory Population 수행한다.

SQL> execute dbms_inmemory.populate('SH','SALES_COLIM');
PL/SQL procedure successfully completed.
 
SQL> select segment_name, bytes, inmemory_size, populate_status, bytes_not_populated from v$im_segments where owner='SH' and segment_name='SALES_COLIM';
SEGMENT_NAME                        BYTES INMEMORY_SIZE POPULATE_STAT BYTES_NOT_POPULATED
------------------------------ ---------- ------------- ------------- -------------------
SALES_COLIM                    7288676352    2549088256 COMPLETED                       0

 

먼저 압축 레벨은 서로 다른 In-Memory 칼럼으로 구성된 쿼리를 수행해 본다. INMEMORY FULL 스캔을 수행했다.

SQL> set pages 0
SQL> set lines 200
SQL> set timing on
SQL> select min(QUANTITY_SOLD), max(AMOUNT_SOLD) from sh.SALES_COLIM where PROD_ID > 100;
                 1               98
 
Elapsed: 00:00:00.08
SQL> select * from table(dbms_xplan.display_cursor());
SQL_ID  asmgp994rfgkn, child number 0
-------------------------------------
select min(QUANTITY_SOLD), max(AMOUNT_SOLD) from sh.SALES_COLIM where
PROD_ID > 100
 
Plan hash value: 4277465842
 
-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |       |       | 10494 (100)|          |
|   1 |  SORT AGGREGATE             |             |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS INMEMORY FULL| SALES_COLIM |    41M|   394M| 10494  (15)| 00:00:01 |
-------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - inmemory("PROD_ID">100)
       filter("PROD_ID">100)
 
21 rows selected.

 

아래와 같이 SELECT 절에 INMEMORY NOINMEMORY 속성의 칼럼이 들어가 있고, Predicate INMEMORY 속성의 칼럼이 들어간 쿼리의 경우, 옵티마이저가 In-Memory hybrid scan 선택하는 것을 있다.

SQL> select max(PROD_ID), max(TAX_REGION) from sh.SALES_COLIM where PROD_ID > 1;
         147 zz
 
Elapsed: 00:01:38.35
SQL> select * from table(dbms_xplan.display_cursor());
SQL_ID  a04rb6r1j8zy0, child number 0
-------------------------------------
select max(PROD_ID), max(TAX_REGION) from sh.SALES_COLIM where PROD_ID
> 1
 
Plan hash value: 4277465842
 
----------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |             |       |       |   242K(100)|          |
|   1 |  SORT AGGREGATE                      |             |     1 |     7 |            |          |
|*  2 |   TABLE ACCESS INMEMORY FULL (HYBRID)| SALES_COLIM |   117M|   786M|   242K  (1)| 00:00:10 |
----------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("PROD_ID">1)
 
20 rows selected.

 

아래와 같이 SELECT 절에는 INMEMORY NOINMEMORY 속성의 칼럼이 들어가 있고, Predicate NO INMEMORY 속성이 들어간 쿼리의 경우에도, 옵티마이저가 In-Memory hybrid scan 선택하는 것을 있다.

SQL> select TAX_COUNTRY, min(QUANTITY_SOLD), max(AMOUNT_SOLD) from sh.SALES_COLIM where PROD_ID > 100 group by TAX_COUNTRY;
dr                   1               98
nb                   1               98
ff                   1               98
hs                   1               98
...
qf                   1               98
id                   1               98
 
676 rows selected.
 
Elapsed: 00:10:02.85
 
SQL> select * from table(dbms_xplan.display_cursor());
SQL_ID  5a70g7mk19pgk, child number 0
-------------------------------------
select TAX_COUNTRY, min(QUANTITY_SOLD), max(AMOUNT_SOLD) from
sh.SALES_COLIM where PROD_ID > 100 group by TAX_COUNTRY
 
Plan hash value: 2450388630
 
----------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |             |       |       |   243K(100)|          |
|   1 |  HASH GROUP BY                       |             |   676 |  8788 |   243K  (1)| 00:00:10 |
|*  2 |   TABLE ACCESS INMEMORY FULL (HYBRID)| SALES_COLIM |    41M|   512M|   242K  (1)| 00:00:10 |
----------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("PROD_ID">100)
 
20 rows selected.

 

NOINMEMORY 칼럼으로 구성된 쿼리의 경우, 테이블은 INMEMORY 속성이라도, 로우 스토어에서 데이터를 읽는다.

SQL> alter system flush buffer_cache;
System altered.
 
Elapsed: 00:00:00.10
SQL> select max(TAX_COUNTRY), max(TAX_REGION) from sh.SALES_COLIM where TAX_COUNTRY > 'qq';
zz  zz
 
Elapsed: 00:01:17.12
 
SQL> select * from table(dbms_xplan.display_cursor());
SQL_ID  8axggudpr9t3x, child number 0
-------------------------------------
select max(TAX_COUNTRY), max(TAX_REGION) from sh.SALES_COLIM where
TAX_COUNTRY > 'qq'
 
Plan hash value: 4277465842
 
----------------------------------------------------------------------------------
| Id  | Operation          | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |             |       |       |   242K(100)|          |
|   1 |  SORT AGGREGATE    |             |     1 |     6 |            |          |
|*  2 |   TABLE ACCESS FULL| SALES_COLIM |    42M|   242M|   242K  (1)| 00:00:10 |
----------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("TAX_COUNTRY">'qq')
 
20 rows selected.

 

<END>