병렬 DDL 처리 가능한 작업

  • CREATE INDEX
  • CREATE TABLE AS SELECT
  • ALTER INDEX REBUILD
  • ALTER TABLE MOVE
  • ALTER TABLE SPLIT/COALESCE PARTITION
  • ALTER INDEX SPLIT PARTITION

병렬 DDL과 External 테이블을 사용한 데이터 로딩

  • 병렬 direct path : 여러 세션이 버퍼 캐시를 거치지 않고, 언두를 생성하지 않은 채 오라클 데이터 파일에 직접 쓰는 방식
  • 병렬 direct path 는 다음과 방식으로 쉽게 할 수 있다.
    • external 테이블
    • CREATE TABLE AS SELECT
예제
{code:sqlborderStyle=solid}
BIG_TABLE@THREE >create table user_info as select * from all_users;

Table created.

BIG_TABLE@THREE >alter table user_info parallel;

Table altered.

BIG_TABLE@THREE >exec dbms_stats.gather_table_stats ( user, 'USER_INFO');

PL/SQL procedure successfully completed.

BIG_TABLE@THREE >explain plan for
2 create table new_table parallel
3 as
4 select a.*, b.user_id, b.created user_created
5 from big_table a, user_info b
6 where a.owner = b.username
7 /

Explained.

BIG_TABLE@THREE >select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
































Plan hash value: 3867074464





























---

IdOperationNameRowsBytesCost (%CPU)TimeTQIN-OUTPQ Distrib





























---

0CREATE TABLE STATEMENT17M1847M30667 (1)00:06:09
1PX COORDINATOR
2PX SEND QC (RANDOM):TQ1000117M1847M18162 (1)00:03:38Q1,01P->SQC (RAND)
3LOAD AS SELECTNEW_TABLEQ1,01PCWP
  • 4
HASH JOIN17M1847M18162 (1)00:03:38Q1,01PCWP
5PX RECEIVE203802 (0)00:00:01Q1,01PCWP
6PX SEND BROADCAST:TQ10000203802 (0)00:00:01Q1,00P->PBROADCAST
7PX BLOCK ITERATOR203802 (0)00:00:01Q1,00PCWC
8TABLE ACCESS FULLUSER_INFO203802 (0)00:00:01Q1,00PCWP
9PX BLOCK ITERATOR17M1536M18136 (1)00:03:38Q1,01PCWC
10TABLE ACCESS FULLBIG_TABLE17M1536M18136 (1)00:03:38Q1,01PCWP





























---

Predicate Information (identified by operation id):













---

4 - access("A"."OWNER"="B"."USERNAME")

22 rows selected.

 |

h1. 병렬 DDL과 익스텐트 트리밍

* 병렬DDL의 각 병렬 실행 서버는 개별의 익스텐트을 할당받고, 자신의 익스텐트에 데이터를 입력한다. 병렬 실행 서버는 다른 병렬 실행 서버가 할당한 익스텐트를 공동으로 사용하지 않는다.

|| 병렬 DDL의 익스텐트 할당 ||
| !3.JPG! |
* 단점 : 데이터 웨어하우스 환경에서는 대량 로드 후 공간 낭비를 일으킬 수 있다.
* 이러한 단점을 보완하기 위해 오라클은 각 병렬 실행 서버의 마지막 익스텐트를 대상으로 가능한 한 가장 작은 크기로 다시 트림을 시도하는 익스텐트 트리밍을 발생한다.

* 테이블스페이스 종류 별 익스텐트 트리밍
** dictionary-managed 테이블스페이스 : 빈공간이 있는 익스텐트가 할지라도 불연속적인 상태이기 때문에 사용되지 않는 않는다.
** locally-managed 테이블스페이스
*** UNIFORM SIZE : 항상 같은 크기만큼 익스텐트를 늘려주는 것으로, 익스텐트 트리밍을 수행하지 않는다.
*** AUTOALLOCATE : 내부 알고리즘을 사용해서 얼마큼 큰 익스텐트를 사용할 것인지 결정한다. 인공 지능 방식은 아니지만 익스텐트 트리밍을 수행한다.
|| 테스트용 external 테이블 생성 ||
| {code:sql|borderStyle=solid}
-- big_table.ctl
LOAD DATA
INFILE '/tmp/big_table.dat'
INTO TABLE big_table
REPLACE
FIELDS TERMINATED BY '|'
(
id, owner, object_name, subobject_name, object_id, data_object_id, object_type,
created, last_ddl_time, timestamp, status, temporary, generated, secondary
)

-- 변환
sqlldr big_table/test big_table.ctl external_table=generate_only

-- big_table.log 의 external 테이블 생성문
CREATE TABLE statement for external table:
------------------------------------------------------------------------
CREATE TABLE "SYS_SQLLDR_X_EXT_BIG_TABLE"
(
  "ID" NUMBER,
  "OWNER" VARCHAR2(30),
  "OBJECT_NAME" VARCHAR2(30),
  "SUBOBJECT_NAME" VARCHAR2(30),
  "OBJECT_ID" NUMBER,
  "DATA_OBJECT_ID" NUMBER,
  "OBJECT_TYPE" VARCHAR2(19),
  "CREATED" DATE,
  "LAST_DDL_TIME" DATE,
  "TIMESTAMP" VARCHAR2(19),
  "STATUS" VARCHAR2(7),
  "TEMPORARY" VARCHAR2(1),
  "GENERATED" VARCHAR2(1),
  "SECONDARY" VARCHAR2(1)
)
ORGANIZATION external
(
  TYPE oracle_loader
  DEFAULT DIRECTORY SYS_SQLLDR_XT_TMPDIR_00000
  ACCESS PARAMETERS
  (
    RECORDS DELIMITED BY NEWLINE CHARACTERSET KO16KSC5601
    BADFILE 'SYS_SQLLDR_XT_TMPDIR_00001':'big_table.bad'
    LOGFILE 'big_table.log_xt'
    READSIZE 1048576
    FIELDS TERMINATED BY "|" LDRTRIM
    REJECT ROWS WITH ALL NULL FIELDS
    (
      "ID" CHAR(255)
        TERMINATED BY "|",
      "OWNER" CHAR(255)
        TERMINATED BY "|",
      "OBJECT_NAME" CHAR(255)
        TERMINATED BY "|",
      "SUBOBJECT_NAME" CHAR(255)
        TERMINATED BY "|",
      "OBJECT_ID" CHAR(255)
        TERMINATED BY "|",
      "DATA_OBJECT_ID" CHAR(255)
        TERMINATED BY "|",
      "OBJECT_TYPE" CHAR(255)
        TERMINATED BY "|",
      "CREATED" CHAR(255)
        TERMINATED BY "|",
      "LAST_DDL_TIME" CHAR(255)
        TERMINATED BY "|",
      "TIMESTAMP" CHAR(255)
        TERMINATED BY "|",
      "STATUS" CHAR(255)
        TERMINATED BY "|",
      "TEMPORARY" CHAR(255)
        TERMINATED BY "|",
      "GENERATED" CHAR(255)
        TERMINATED BY "|",
      "SECONDARY" CHAR(255)
        TERMINATED BY "|"
    )
  )
  location
  (
    'big_table.dat'
  )
)REJECT LIMIT UNLIMITED

-- 디렉토리명, 테이블명 변경한 테이블 생성문
BIG_TABLE@THREE >create or replace directory my_dir as '/tmp/'
  2  /

Directory created.

CREATE TABLE "BIG_TABLE_ET"
(
  "ID" NUMBER,
  "OWNER" VARCHAR2(30),
  "OBJECT_NAME" VARCHAR2(30),
  "SUBOBJECT_NAME" VARCHAR2(30),
  "OBJECT_ID" NUMBER,
  "DATA_OBJECT_ID" NUMBER,
  "OBJECT_TYPE" VARCHAR2(19),
  "CREATED" VARCHAR2(30), <- 데이터 형 변경 ( date -> varchar2)
  "LAST_DDL_TIME" VARCHAR2(30), <- 데이터 형 변경 ( date -> varchar2)
  "TIMESTAMP" VARCHAR2(19),
  "STATUS" VARCHAR2(7),
  "TEMPORARY" VARCHAR2(1),
  "GENERATED" VARCHAR2(1),
  "SECONDARY" VARCHAR2(1)
)
ORGANIZATION external
(
  TYPE oracle_loader
  DEFAULT DIRECTORY my_dir
  ACCESS PARAMETERS
  (
    RECORDS DELIMITED BY NEWLINE CHARACTERSET KO16KSC5601
    READSIZE 1048576
    FIELDS TERMINATED BY "|" LDRTRIM
    REJECT ROWS WITH ALL NULL FIELDS
  )
  location
  (
    'big_table.dat'
  )
)REJECT LIMIT UNLIMITED
/

Table created.

-- 테이블에 병렬 설정
BIG_TABLE@THREE >alter table BIG_TABLE_ET parallel;

Table altered.

|

locally-managed 테이블스페이스의 uniform 익스텐트 트리밍 vs. autoallocate 익스텐트 트리밍 비교 테스트
{code:sqlborderStyle=solid}
-- 각 테이블스페이스 생성
SYS@THREE >create tablespace lmt_uniform
2 datafile '/data01/oradata/THREE/lmt_uniform.dbf' size 1048640K reuse
3 autoextend on next 100m
4 extent management local
5 uniform size 100m;

Tablespace created.

SYS@THREE >create tablespace lmt_auto
2 datafile '/data01/oradata/THREE/lmt_auto.dbf' size 1048640K reuse
3 autoextend on next 100m
4 extent management local
5 autoallocate;

Tablespace created.

– load할 flat파일
oracle@primarydb big_table$ ls -al /tmp/big_table.dat
rw-rr- 1 oracle dba 2109876644 Dec 7 15:08 /tmp/big_table.dat

– uniform, autoallocate 두 테이블스페이스에 병렬 direct path 로드로 테이블 생성
BIG_TABLE@THREE >create table uniform_test
2 parallel
3 tablespace lmt_uniform
4 as
5 select * from big_table_et;

Table created.

– external 테이블 로그 파일을 통하 병렬 모니터링
oracle@primarydb tmp$ ls -ltr
rw-rr- 1 oracle dba 1801 Dec 7 17:31 BIG_TABLE_ET_28935.log
rw-rr- 1 oracle dba 1801 Dec 7 17:31 BIG_TABLE_ET_28884.log

– v$px_session를 통한 병렬 처리 모니터링

  • CPU(2) * parallel_threads_per_cpu : 4개의 병렬 실행 서버

SYS@THREE >select sid, serial#, qcsid, qcserial#, degree
2 from v$px_session;

SID SERIAL# QCSID QCSERIAL# DEGREE



--

--

--

--

--
23 31 16 27 4
18 29 16 27 4
790 5 16 27 4
22 19 16 27 4
16 27 16

SYS@THREE >show parameter parallel_threads_per_cpu

NAME TYPE VALUE












---






--
parallel_threads_per_cpu integer 2

--사용 공간 비교
BIG_TABLE@THREE >select segment_name, blocks, extents
2 from user_segments
3 where segment_name in ( 'UNIFORM_TEST', 'AUTOALLOCATE_TEST');

SEGMENT_NAME BLOCKS EXTENTS








--

--

--
UNIFORM_TEST 294400 23
AUTOALLOCATE_TEST 290032 219

--UNIFORM_TEST : 각 익스텐트의 크기는 100MB
BIG_TABLE@THREE >select segment_name, extent_id, blocks
2 from user_extents where segment_name = 'UNIFORM_TEST';

SEGMENT_NAME EXTENT_ID BLOCKS








--

--

--
UNIFORM_TEST 0 12800
UNIFORM_TEST 1 12800
UNIFORM_TEST 2 12800
UNIFORM_TEST 3 12800
UNIFORM_TEST 4 12800
UNIFORM_TEST 5 12800
UNIFORM_TEST 6 12800
UNIFORM_TEST 7 12800
UNIFORM_TEST 8 12800
UNIFORM_TEST 9 12800
UNIFORM_TEST 10 12800
UNIFORM_TEST 11 12800
UNIFORM_TEST 12 12800
UNIFORM_TEST 13 12800
UNIFORM_TEST 14 12800
UNIFORM_TEST 15 12800
UNIFORM_TEST 16 12800
UNIFORM_TEST 17 12800
UNIFORM_TEST 18 12800
UNIFORM_TEST 19 12800
UNIFORM_TEST 20 12800
UNIFORM_TEST 21 12800
UNIFORM_TEST 22 12800

23 rows selected.

--AUTOALLOCATE_TEST : 할당한 extents의 수가 219, 집계결과
BIG_TABLE@THREE >select segment_name, blocks, count(*)
2 from user_extents
3 where segment_name = 'AUTOALLOCATE_TEST'
4 group by segment_name, blocks
5 order by blocks;

SEGMENT_NAME BLOCKS COUNT(*)








--

--

--
AUTOALLOCATE_TEST 8 16
AUTOALLOCATE_TEST 128 63
AUTOALLOCATE_TEST 1024 120
AUTOALLOCATE_TEST 3312 1
AUTOALLOCATE_TEST 8192 19

  • show_space 프로시저 실패로 상세 공간 정보는 추후에...
 |

{note:title=*요약*}
1. 병렬 환경에서는 AUTOALLOCATE 방식으로 익스텐트 관리하는 것이 좋다.
2. UNIFORM 방식은 익스텐트를 더 작게 할당할 수 있지만, 시간이 지남에 따라 공간의 낭비가 발생하게 되고 이 공간이 테이블의 전체 스캔에 포함된다.
{note}