대량의 DML 작업에대한성능개선방안 엑셈컨설팅본부 /DB 컨설팅팀박준연 개요 대량의데이터를변경해야하는작업은그자체만으로도큰부담으로다가온다. 하지만변경작업자체에만국한되는것이아니라변경되기전데이터와변경이후데이터를각각저장관리해야하는메커니즘이라면성능을개선해야하는입장에서는더욱큰부담

Similar documents
歯sql_tuning2

Result Cache 동작원리및활용방안 엑셈컨설팅본부 /DB 컨설팅팀김철환 개요 ORACLE DBMS 를사용하는시스템에서 QUERY 성능은무엇보다중요한요소중하나이며그 성능과직접적인관련이있는것이 I/O 이다. 많은건수를 ACCESS 해야만원하는결과값을얻을수있는 QUER

13주-14주proc.PDF

Bind Peeking 한계에따른 Adaptive Cursor Sharing 등장 엑셈컨설팅본부 /DB 컨설팅팀김철환 Bind Peeking 의한계 SQL 이최초실행되면 3 단계의과정을거치게되는데 Parsing 단계를거쳐 Execute 하고 Fetch 의과정을통해데이터

WINDOW FUNCTION 의이해와활용방법 엑셈컨설팅본부 / DB 컨설팅팀정동기 개요 Window Function 이란행과행간의관계를쉽게정의할수있도록만든함수이다. 윈도우함수를활용하면복잡한 SQL 들을하나의 SQL 문장으로변경할수있으며반복적으로 ACCESS 하는비효율역

ORACLE EXADATA HCC 압축방식이해하기 엑셈컨설팅본부 /DB 컨설팅팀김철환 개요 시간이지나면서데이터는급속하게증가하고있다. 데이터가증가함에따라 DBMS 에서관리되어지는정보도급속하게증가하고있다. 이로인해저장공간의부족으로하드웨어비용의증가와데이터처리성능에많은문제점들

Commit_Wait / Commit_Logging 두파라미터를통해 Log File Sync 대기시간을감소시킬수있다는것은놀라움과의아함을동시에느낄수있다. 단지파라미터의수정을통해당연히대기해야하는시간을감축한다는것은분명성능을개선해야하는입장에서는놀라운일이될것이다. 반면, 그에따

90

10.ppt

목차 BUG offline replicator 에서유효하지않은로그를읽을경우비정상종료할수있다... 3 BUG 각 partition 이서로다른 tablespace 를가지고, column type 이 CLOB 이며, 해당 table 을 truncate

목차 BUG 문법에맞지않는질의문수행시, 에러메시지에질의문의일부만보여주는문제를수정합니다... 3 BUG ROUND, TRUNC 함수에서 DATE 포맷 IW 를추가지원합니다... 5 BUG ROLLUP/CUBE 절을포함하는질의는 SUBQUE

MS-SQL SERVER 대비 기능

기술노트 49 회 SQL PLAN MANAGEMENT Author 윤병길과장 Creation Date Last Updated Version 1.0 Copyright(C) 2009 Goodus Inc. All Rights Reserved

배치프로그램에서튜닝대상 SQL 추출하기 엑셈컨설팅본부 /DB 컨설팅팀박성호 배치프로그램의성능문제를진단하기위해트레이스를사용할수없고, 개별 SQL 에대한성 능점검은비효율적인경우에어떻게배치프로그램의성능문제를제대로파악하고개선안을도 출할것인가? 복잡한로직을가지고있는프로그램 (

SQL Server 에서 SQL 튜닝시알아야할힌트와사용 방법 엑셈컨설팅본부 /DB 컨설팅팀박성호 Optimizer 가 SQL 을해석할때항상최적의실행계획을생성하지는못한다. 복잡한 SQL 일수록최적의실행계획을생성하기위해고려해야할대상 (Table, Index 가많은경우 )

ORANGE FOR ORACLE V4.0 INSTALLATION GUIDE (Online Upgrade) ORANGE CONFIGURATION ADMIN O

PowerPoint 프레젠테이션

원장 차세대 필요성 검토

InsertColumnNonNullableError(#colName) 에해당하는메시지출력 존재하지않는컬럼에값을삽입하려고할경우, InsertColumnExistenceError(#colName) 에해당하는메시지출력 실행결과가 primary key 제약에위배된다면, Ins

DBMS & SQL Server Installation Database Laboratory

Microsoft PowerPoint - 10Àå.ppt

PowerPoint Presentation

Microsoft Word - [Unioneinc] 특정컬럼의 통계정보 갱신_ _ldh.doc

ALTIBASE HDB Patch Notes

다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL

untitled

강의 개요

1. 들어가며 많은기업들이정보시스템의근간으로데이터베이스를사용하고있고또많은사람들이데이터베이스의성능에대해불만을토로한다. 데이터베이스의성능문제와관련해많은원인과해결책이있지만이문제와관련해자주언급되는개념이있다. Hard Parsing 이그것이다. Hard Parsing 은성능에좋

@OneToOne(cascade = = "addr_id") private Addr addr; public Emp(String ename, Addr addr) { this.ename = ename; this.a

untitled

最即時的Sybase ASE Server資料庫診斷工具

목 차

<4D F736F F D203033C6C4C6BCBCC72DB8AEBFC0B1D7B9E6B9FD2E646F63>

MySQL-.. 1

문서 템플릿

Tablespace On-Offline 테이블스페이스 온라인/오프라인

Connection 8 22 UniSQLConnection / / 9 3 UniSQL OID SET

다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL

6장. SQL

PowerPoint 프레젠테이션

Oracle Database 10g: Self-Managing Database DB TSC

SQL Tuning Business Development DB

Jerry Held

윈도우시스템프로그래밍

ePapyrus PDF Document

슬라이드 1

Microsoft PowerPoint - Oracle Data Access Pattern.ppt

SQL PLAN MANAGEMENT 활용 엑셈컨설팅본부 /DB 컨설팅팀장정민 개요 오라클은비롯한많은관계형 DBMS 에서는사용자의 SQL 질의를효율적으로처리하기위해옵티마이저를사용하고있다. 옵티마이저는유저가수행하는 SQL 을받아실행계획을생성하고, 실제 SQL 은이실행계획을

ETL_project_best_practice1.ppt

KEEP BUFFER 활용방안 엑셈컨설팅본부 /DB 컨설팅팀장정민 개요 Oracle 은유저가요청한작업을빠르게처리하기위해 Buffer Cache 라는것을사용한다. Buffer Cache 는 SGA 에위치하고있으며, 오라클인스턴스에접속하는모든프로세스에의해공유된다. 이 Bu

결과보고서

3 S Q L A n t i p a t t e r n s Trees/intro/parent.sql CREATE TABLE Comments ( comment_id SERIAL PRIMARY KEY, parent_id BIGINT UNSIGNED, comment TEXT

PowerPoint 프레젠테이션

NLJ BATCH 과부분범위처리 엑셈컨설팅본부 / DB 컨설팅팀오수영 개요 오라클은새로운버전이출시될때마다한층업그레이드된기능들이추가된다. 이기능들은사용자에게편리함을제공함은물론이고, 기존의기능들이성능적으로업그레이드되어보다강력해지기도한다. 그러나때로는새롭게추가된기능으로인해,

The Self-Managing Database : Automatic Health Monitoring and Alerting

PRO1_09E [읽기 전용]

Microsoft Word - SQL튜닝_실습교재_.doc

TITLE

초보자를 위한 분산 캐시 활용 전략

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

Microsoft Word - PLSQL.doc

PowerPoint Presentation

DB 성능고도화핵심원리 비투엔컨설팅 수석컨설턴트 조시형


FlashBackt.ppt


다양한 예제로 쉽게 배우는 오라클 SQL 과 PL/SQL

Microsoft PowerPoint Python-DB

<C1A62038B0AD20B0ADC0C7B3EBC6AE2E687770>

그리고.. 엑셀에하나둘완료된쿼리가늘어날때마다... 희열을느낀다... 이글을보는당신은어떻게할것인가? A 군의판단이잘못된것인가? 잘못된판단이아니다최선의판단이다... 11g 전까지는... 11g New Feature 인 Pending Statistics 를 SPA 와함께사용

I T C o t e n s P r o v i d e r h t t p : / / w w w. h a n b i t b o o k. c o. k r

윈도우시스템프로그래밍

Data Sync Manager(DSM) Example Guide Data Sync Manager (DSM) Example Guide DSM Copyright 2003 Ari System, Inc. All Rights reserved. Data Sync Manager

6주차.key

ALTIBASE HDB Patch Notes

Intra_DW_Ch4.PDF

윈백및업그레이드 Tibero Flashback 가이드

5장 SQL 언어 Part II

SQL Developer Connect to TimesTen 유니원아이앤씨 DB 기술지원팀 2010 년 07 월 28 일 문서정보 프로젝트명 SQL Developer Connect to TimesTen 서브시스템명 버전 1.0 문서명 작성일 작성자

제목을 입력하세요.

DW 개요.PDF

Simplify your Job Automatic Storage Management DB TSC

MySQL-Ch10

62

thesis

Microsoft Word - 05_SUBPROGRAM.doc

PowerPoint Presentation

Slide 1

Microsoft Word - 04_EXCEPTION.doc

Æí¶÷4-¼Ö·ç¼Çc03ÖÁ¾š

歯PLSQL10.PDF

ALTIBASE HDB Patch Notes

단답형 (26 회기출문제 ) 1. 아래와같은테이블이있을때아래의 SQL 결과에대해서 Oracle, SQL Server 순서로적으시오 TAB1 COL1 CHAR(10) COL2 CHAR(10) INSERT INTO TAB1 VALUES ('1',''); INSERT INT

쉽게 풀어쓴 C 프로그래밊

K7VT2_QIG_v3

chap 5: Trees

PowerPoint Presentation

Remote UI Guide

Jerry Held

Spring Boot/JDBC JdbcTemplate/CRUD 예제

Transcription:

대량의 DML 작업에대한성능개선방안 엑셈컨설팅본부 /DB 컨설팅팀박준연 개요 대량의데이터를변경해야하는작업은그자체만으로도큰부담으로다가온다. 하지만변경작업자체에만국한되는것이아니라변경되기전데이터와변경이후데이터를각각저장관리해야하는메커니즘이라면성능을개선해야하는입장에서는더욱큰부담일것이다. 말그대로대량의데이터를변경해야하는작업의특성상 SQL Tuning 만으로성능을개선할여지는많지않을뿐더러개선을한다하더라도극적인효과를기대하기는어렵다. 더욱이필연적으로발생하는 redo 와 undo 데이터로인한추가적인부하는성능을개선해야하는입장에서는오라클의합리적인동시성보장메커니즘이오히려원망스럽게느껴질법도하다. 따라서, 이번주제는대량의 DML 을처리할때, 파티션테이블의구성및변경이나 Direct Path Insert 를유도하는방법등을통하여 DML 작업자체의성능개선은물론이고, 시스템의 Down Time 최소화에도기여할수있는방법에대한이야기를하고자한다. 대량의 Delete 월단위혹은특정기간단위의데이터를주기적으로삭제하는업무는어느시스템에서나쉽게 볼수있는작업중하나이다. 익숙한작업이긴하나그작업의성능을개선하기란쉽지않다. 대량의 Delete 작업은 Table Full Scan 이나 Index Scan 등과같은해당테이블을 Access 하는방법에의한비효율보다는필연적으로발생할수밖에없는 redo, undo 데이터생성과더불어해당테이블에인덱스가존재한다면인덱스의개수에따라추가적인 Overhead 가발생하는것이성능저하의주된이유가되기때문이다. 인덱스에서발생하는추가적인 Overhead 란, 삭제대상이되는데이터를인덱스에서도삭제해 야하는것과동시에, 이과정역시 redo 와 undo 데이터가생성됨을의미한다. Part 1 ORACLE 95

위와같은부하를억제하면서대량의 Delete 작업의수행속도를개선하려면어떤방법이있을까? 답은 Partition Table 구성에있다. 주기적으로삭제해야하는기간이정해져있다면, 해당칼럼을 Key 로하는 Range Partition 을 구성하고, 삭제대상이되는기간에해당하는 Partition Table 을 Alter Table [Partition_Name] Drop Partition [Partition_Name] 명령을통해 DML 이아닌 DDL 로작업을대체할수있다. DDL 로의 Delete 작업의대체는, redo 데이터가생성되지않고단순히해당 Partition 을 Drop 하는작업만수행하므로속도의차이는비교할수없을만큼크고, 많은양의 redo / undo 데이 터가발생되지않으므로 Down Time 최소화에도큰기여를할수있다. 아래테스트를통해그차이에대해서상세히알아보자. 테이블생성 DDL (Partition_test) CREATE TABLE partition_test (TIME_ID DATE, DAY_NAME VARCHAR2(9), DAY_NUMBER_IN_WEEK NUMBER(1,0), DAY_NUMBER_IN_MONTH NUMBER(2,0), CALENDAR_WEEK_NUMBER NUMBER(2,0), FISCAL_WEEK_NUMBER NUMBER(2,0), WEEK_ENDING_DAY DATE, WEEK_ENDING_DAY_ID NUMBER, CALENDAR_MONTH_NUMBER NUMBER(2,0), FISCAL_MONTH_NUMBER NUMBER(2,0), CALENDAR_MONTH_DESC VARCHAR2(8), CALENDAR_MONTH_ID NUMBER, FISCAL_MONTH_DESC VARCHAR2(8), FISCAL_MONTH_ID NUMBER, DAYS_IN_CAL_MONTH NUMBER, DAYS_IN_FIS_MONTH NUMBER, END_OF_CAL_MONTH DATE, END_OF_FIS_MONTH DATE, CALENDAR_MONTH_NAME VARCHAR2(9), FISCAL_MONTH_NAME VARCHAR2(9), CALENDAR_QUARTER_DESC CHAR(7), CALENDAR_QUARTER_ID NUMBER, FISCAL_QUARTER_DESC CHAR(7), 96 2013 기술백서 White Paper

FISCAL_QUARTER_ID NUMBER, DAYS_IN_CAL_QUARTER NUMBER, DAYS_IN_FIS_QUARTER NUMBER, END_OF_CAL_QUARTER DATE, END_OF_FIS_QUARTER DATE, CALENDAR_QUARTER_NUMBER NUMBER(1,0), FISCAL_QUARTER_NUMBER NUMBER(1,0), CALENDAR_YEAR NUMBER(4,0), CALENDAR_YEAR_ID NUMBER, FISCAL_YEAR NUMBER(4,0), FISCAL_YEAR_ID NUMBER, DAYS_IN_CAL_YEAR NUMBER, DAYS_IN_FIS_YEAR NUMBER, END_OF_CAL_YEAR DATE, END_OF_FIS_YEAR DATE ) PARTITION BY RANGE( time_id )( PARTITION partition_test1 VALUES less than (to_date('1998-12-31','yyyy-mm-dd')), PARTITION partition_test2 VALUES less than (to_date('1999-12-31','yyyy-mm-dd')), PARTITION partition_test3 VALUES less than (to_date('2000-12-31','yyyy-mm-dd')), PARTITION partition_test4 VALUES less than (to_date('2001-12-31','yyyy-mm-dd')), PARTITION partition_test5 VALUES less than (to_date('2003-12-31','yyyy-mm-dd')) ); 테이블생성 DDL (Partition_test2) CREATE TABLE partition_test2 (TIME_ID DATE, DAY_NAME VARCHAR2(9), DAY_NUMBER_IN_WEEK NUMBER(1,0), DAY_NUMBER_IN_MONTH NUMBER(2,0), CALENDAR_WEEK_NUMBER NUMBER(2,0), FISCAL_WEEK_NUMBER NUMBER(2,0), WEEK_ENDING_DAY DATE, WEEK_ENDING_DAY_ID NUMBER, CALENDAR_MONTH_NUMBER NUMBER(2,0), FISCAL_MONTH_NUMBER NUMBER(2,0), CALENDAR_MONTH_DESC VARCHAR2(8), CALENDAR_MONTH_ID NUMBER, FISCAL_MONTH_DESC VARCHAR2(8), FISCAL_MONTH_ID NUMBER, DAYS_IN_CAL_MONTH NUMBER, DAYS_IN_FIS_MONTH NUMBER, END_OF_CAL_MONTH DATE, Part 1 ORACLE 97

END_OF_FIS_MONTH DATE, CALENDAR_MONTH_NAME VARCHAR2(9), FISCAL_MONTH_NAME VARCHAR2(9), CALENDAR_QUARTER_DESC CHAR(7), CALENDAR_QUARTER_ID NUMBER, FISCAL_QUARTER_DESC CHAR(7), FISCAL_QUARTER_ID NUMBER, DAYS_IN_CAL_QUARTER NUMBER, DAYS_IN_FIS_QUARTER NUMBER, END_OF_CAL_QUARTER DATE, END_OF_FIS_QUARTER DATE, CALENDAR_QUARTER_NUMBER NUMBER(1,0), FISCAL_QUARTER_NUMBER NUMBER(1,0), CALENDAR_YEAR NUMBER(4,0), CALENDAR_YEAR_ID NUMBER, FISCAL_YEAR NUMBER(4,0), FISCAL_YEAR_ID NUMBER, DAYS_IN_CAL_YEAR NUMBER, DAYS_IN_FIS_YEAR NUMBER, END_OF_CAL_YEAR DATE, END_OF_FIS_YEAR DATE ); 데이터입력 ( 두테이블동일 ) INSERT /*+ append */ INTO partition_test SELECT a.* FROM sh.times a, ( SELECT LEVEL FROM dual CONNECT BY LEVEL <= 10000 ) b; 일반테이블 (Partition_test2) 의데이터삭제 SQL> delete partition_test2 2 where time_id<= (to_date('2000-12-31','yyyy-mm-dd')); 10960000 행이삭제되었습니다. Execution Plan 98 2013 기술백서 White Paper

---------------------------------------------------------- Plan hash value: 3385385008 -------------------------------------------------------------------------------------- Id Operation Name Rows Bytes Cost (%CPU) Time -------------------------------------------------------------------------------------- 0 DELETE STATEMENT 5718 51462 141K (1) 00:28:15 1 DELETE PARTITION_TEST2 * 2 TABLE ACCESS FULL PARTITION_TEST2 5718 51462 141K (1) 00:28:15 -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("time_id"<=to_date(' 2000-12-31 00:00:00', 'syyyy-mm-ddhh24:mi:ss')) Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 5516 recursive calls 13289330 db block gets 521869 consistent gets 520081 physical reads 5831072716 redo size 565 bytes sent via SQL*Net to client 544 bytes received via SQL*Net from client 3 SQL*Net roundtrips to/from client 7 sorts (memory) 0 sorts (disk) 10960000 rows processed 파티션테이블 (Partition_test) 의데이터삭제 SQL> alter table partition_test drop partition partition_test1; 테이블이변경되었습니다. SQL> alter table partition_test drop partition partition_test2; 테이블이변경되었습니다. SQL> alter table partition_test drop partition partition_test3; Part 1 ORACLE 99

테이블이변경되었습니다. 대량의 INSERT 대량의데이터를 Insert 하는작업은위에서소개한 Delete 작업에비해성능개선의여지가많은편이다. 이는데이터입력대상테이블의속성변경 (Nologging) 과힌트 (/*+ append */) 만으로 Direct Path Insert 를유도하여 redo 발생을억제하는방법이있기때문이다. 하지만여기에또다른암초가존재하는데, 이는인덱스의존재다. 이는대량의 Insert 작업시데이터가테이블에입력되는작업보다도인덱스의개수와인덱스의 성격에따라성능이좌우된다고해도무리가아니기때문이다. Direct Path Insert 가가능한환경에서두가지경우에대한대량의 Insert 작업의성능차이와 이를개선하는방법에대해서알아보고자한다. 인덱스의개수에따른 Direct Path Insert 성능차이 Insert 대상이되는테이블에인덱스가다수생성되어있다면그만큼의 redo 발생량이뒤따를 것이므로자연스레 Insert 작업이더뎌질것이다. 아래테스트를통해인덱스개수에따라 Direct Path Insert 작업의속도에어느정도영향을미 치는지알아보자. 테이블생성 DDL 생략 ( 위대량의 Delete 의 Partition_test 테이블 DDL 참조 ) 세개의인덱스가존재하는경우의대량의 Insert SQL> alter table partition_testnologging; 테이블이변경되었습니다. SQL> INSERT /*+ append */ 100 2013 기술백서 White Paper

2 INTO partition_test 3 SELECT a.* 4 FROM sh.times a, 5 ( 6 SELECT LEVEL 7 FROM dual 8 CONNECT BY LEVEL <= 10000 9 ) b; 18260000 개의행이만들어졌습니다. 경과 : 00:08:50.77 Statistics ---------------------------------------------------------- 37399 recursive calls 4600992 db block gets 323059 consistent gets 493284 physical reads 5177833936 redo size 564 bytes sent via SQL*Net to client 636 bytes received via SQL*Net from client 3 SQL*Net roundtrips to/from client 3 sorts (memory) 3 sorts (disk) 18260000 rows processed 기존의인덱스를삭제하고 Insert 이후인덱스생성 SQL> truncate table partition_test; 테이블이잘렸습니다. 경과 : 00:00:00.74 SQL> drop index idx_test1; 인덱스가삭제되었습니다. 경과 : 00:00:00.09 SQL> drop index idx_test2; 인덱스가삭제되었습니다. 경과 : 00:00:00.03 Part 1 ORACLE 101

SQL> drop index idx_test3; 인덱스가삭제되었습니다. 경과 : 00:00:00.03 SQL> INSERT /*+ append */ 2 INTO partition_test 3 SELECT a.* 4 FROM sh.times a, 5 ( 6 SELECT LEVEL 7 FROM dual 8 CONNECT BY LEVEL <= 10000 9 ) b; 18260000 개의행이만들어졌습니다. 경과 : 00:00:24.49 Statistics ---------------------------------------------------------- 13820 recursive calls 532991 db block gets 4210 consistent gets 7 physical reads 1975520 redo size 566 bytes sent via SQL*Net to client 636 bytes received via SQL*Net from client 3 SQL*Net roundtrips to/from client 20 sorts (memory) 0 sorts (disk) 18260000 rows processed SQL> create index idx_test1 on partition_test(time_id, day_name) local; 인덱스가생성되었습니다. 경과 : 00:00:26.87 SQL> create index idx_test2 on partition_test(day_number_in_week,day_number_in_month) local; 인덱스가생성되었습니다. 경과 : 00:00:27.42 SQL> create index idx_test3 on partition_test(week_ending_day,week_ending_day_id) 102 2013 기술백서 White Paper

local; 인덱스가생성되었습니다. 경과 : 00:00:26.72 위테스트결과와같이대량의데이터가입력될때, 해당테이블의인덱스가얼마나많이존재하는지에따라성능에큰영향을주는것으로나타났다. 이는단순히대량의데이터입력시에인덱스의존재에따른성능차이를보여주는테스트이므로대량의데이터가입력되는모든작업에인덱스를 Drop 하거나 Unusable 상태로변경하고작업하라는의미는아니다. 다만, 온라인사용자가없는시간대의배치작업이라면충분히고려할수있는방법이라고생각 한다. 수행속도는물론이거니와 redo 발생의최소화에도큰기여를할수있는장점이있기때문 이다. 빈번한 Index Split에따른 Direct Path Insert 성능차이항상증가하는값을 Insert 해야하는성격의칼럼이존재할수있다. 대표적인예는날자칼럼에 SYSDATE 가입력되는상황일것이다. 만약, 이칼럼에 Index 가생성되어있다고가정하고, 대량의 Insert 작업이수행된다면 9:1 Index Split 이빈번하게발생하는현상이자연스레나타날것이다. 앞서언급했듯이, Index Split 은결코가볍지만은않다. 왜가볍지않은지그과정을살펴보자. 우선, 9:1 Split 이란 Max 값이입력되는상황에서우측최하위 Index Leaf Block 에더이상저장할공간이없는경우 Free List 의 Free Block 을가지고와서기존최하위 Index Leaf Block 의최소한의데이터를새로운 Free Block 에옮겨담고새로저장되는데이터를해당 Block 에입력하는과정을말한다. 이는데이터가증가하는과정에서필연적으로 Index Size 가증가하며, Index Split 은이과정 에서발생하는자연스러운현상이다. 하지만, Index Split 과정은공짜가아니다. Part 1 ORACLE 103

Index Split 의전과정은 redo 가발생하고 Split 이시작되고완료되는시점까지 Locking 을통 해이작업을보호한다. 이 Locking 은, Enq : TX Index Contention 이라는 Wait Event 로 Split 이완료되는시점까지 Split 과정을보호하게된다. 따라서, 항상증가하는성격의칼럼에인덱스가생성되어있고해당테이블에대량의데이터가 입력되는경우, Index Split 에의한 Wait Time 증가와더불어 redo 발생등으로 Insert 속도의 저하는필연적으로발생한다. 그렇다면이를개선할수있는방안이있을까? 결론부터이야기하면문제가되는 Index 에다른 칼럼을추가하여재생성하는방법이존재한다. 이방법의목적은대량의데이터가입력될때, 기존우측최하위 Index Leaf Block 에경합이집중되던것이결합인덱스로인하여그경합이어느정도분산될것이기때문이다. 새로결합할 Index 구성대상칼럼의 NDV(Number of Distinct Value) 값이클수록 Index Split 감소의효과는더욱커질것이다. 다만, 이부분에서주의할것은 Index Clustering Factor 가크게감소할수있으므로 NDV 값이 큰칼럼을우선순위로구성할필요는없다. Array Processing 대량의 DML 작업은데이터를 Load 하거나 Update(Delete) 할때일반적으로 LOOP 문을사용하여건건이처리하는경우가많다. 이방법은매 Loop 마다 1 회씩 DML 작업이수행되어그만큼의 DBMS CALL 이발생하기때문에성능상불리하다. 하지만 Array Processing 을이용한 Bulk SQL 을사용하면 Loop 없이단한번의 SQL 수행만으로처리가가능하다. 즉, 대량의 DML 을단한번 (Limit 예약어를사용하여한번에처리할수있는건수를제한하지않는경우 ) 에처리할수있으므로 DBMS CALL 을감소시켜 Loop 로처리되던방법에비해큰성능개선효과를볼수있다. 아래테스트를통해그성능차이를비교해보자. 104 2013 기술백서 White Paper

Array Processing 을활용하여 Insert 하는 Procedure Source - P_BULK_INSERT_TEST1 CREATE OR REPLACE PROCEDURE P_BULK_INSERT_TEST1 IS CURSOR sales_cur IS SELECT PROD_ID, CUST_ID, TIME_ID, CHANNEL_ID, PROMO_ID, QUANTITY_SOLD, AMOUNT_SOLD FROM SH.SALES; TYPE SALES_TBL_TYPE IS TABLE OF sales_cur%rowtype INDEX BY BINARY_INTEGER; SALES_TBL SALES_TBL_TYPE; BEGIN OPEN sales_cur; LOOP FETCH sales_cur BULK COLLECT INTO sales_tbl LIMIT 1000; -- PGA 소모를작게유지하기위해 1000 건씩만처리 FOR i IN sales_tbl.first..sales_tbl.last LOOP --각종계산은여기에서 sales_tbl(i).amount_sold := sales_tbl(i).amount_sold * 1.5; END LOOP; -- FETCH 된 1000 건을 SQL 1 회수행으로처리 FORALL i IN sales_tbl.first..sales_tbl.last INSERT INTO SALES2 VALUES (sales_tbl(i).prod_id, sales_tbl(i).cust_id, sales_tbl(i).time_id, sales_tbl(i).channel_id, sales_tbl(i).promo_id, sales_tbl(i).quantity_sold, sales_tbl(i).amount_sold ); EXIT WHEN sales_cur%notfound; END LOOP; CLOSE sales_cur; COMMIT; EXCEPTION Part 1 ORACLE 105

WHEN OTHERS THEN ROLLBACK; RAISE_APPLICATION_ERROR(-20001,'RAISE_APPLICATION_ERROR : ' SQLCODE ':' SUBSTR(SQLERRM,1,200)); END; / 건건이 Loop 를통해 Insert 하는 Procedure Source - P_BULK_INSERT_TEST2 CREATE OR REPLACE PROCEDURE P_BULK_INSERT_TEST2 IS CURSOR sales_cur IS SELECT PROD_ID, CUST_ID, TIME_ID, CHANNEL_ID, PROMO_ID, QUANTITY_SOLD, AMOUNT_SOLD FROM SH.SALES; TYPE SALES_TBL_TYPE IS TABLE OF sales_cur%rowtype INDEX BY BINARY_INTEGER; SALES_TBL SALES_TBL_TYPE; BEGIN OPEN sales_cur; LOOP FETCH sales_cur BULK COLLECT INTO sales_tbl LIMIT 1000; -- PGA 소모를작게유지하기위해 1000 건씩만처리 FOR i IN sales_tbl.first..sales_tbl.last LOOP --각종계산은여기에서 sales_tbl(i).amount_sold := sales_tbl(i).amount_sold * 1.5; END LOOP; -- LOOP 를사용하는방법 ; INSERT SQL 1000 번수행 FOR i IN sales_tbl.first..sales_tbl.last LOOP -- FORALL 예약어배제 INSERT INTO SALES2 VALUES (sales_tbl(i).prod_id, sales_tbl(i).cust_id, sales_tbl(i).time_id, sales_tbl(i).channel_id, sales_tbl(i).promo_id, sales_tbl(i).quantity_sold, sales_tbl(i).amount_sold ); 106 2013 기술백서 White Paper

END LOOP; EXIT WHEN sales_cur%notfound; END LOOP; CLOSE sales_cur; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE_APPLICATION_ERROR(-20001,'RAISE_APPLICATION_ERROR : ' SQLCODE ':' SUBSTR(SQLERRM,1,200)); END; / P_BULK_INSERT_TEST2 Vs. P_BULK_INSERT_TEST2 SQL> exec P_BULK_INSERT_TEST1; PL/SQL 처리가정상적으로완료되었습니다. 경과 : 00:00:02.20 SQL> SQL> SQL> exec P_BULK_INSERT_TEST2; PL/SQL 처리가정상적으로완료되었습니다. 경과 : 00:00:35.08 참고 : Array Processing 을활용한 Update Procedure Source CREATE OR REPLACE PROCEDURE P_BULK_INSERT_TEST2 IS CURSOR sales_cur IS SELECT PROD_ID, CUST_ID, TIME_ID, CHANNEL_ID, PROMO_ID, QUANTITY_SOLD, AMOUNT_SOLD FROM SH.SALES; Part 1 ORACLE 107

TYPE SALES_TBL_TYPE IS TABLE OF sales_cur%rowtype INDEX BY BINARY_INTEGER; SALES_TBL SALES_TBL_TYPE; BEGIN OPEN sales_cur; LOOP FETCH sales_cur BULK COLLECT INTO sales_tbl LIMIT 1000; -- PGA 소모를작게유지하기위해 1000 건씩만처리 FOR i IN sales_tbl.first..sales_tbl.last LOOP --각종계산은여기에서 sales_tbl(i).amount_sold := sales_tbl(i).amount_sold * 1.5; END LOOP; -- UPDATE / DELETE 도가능 FORALL i IN sales_tbl.first..sales_tbl.last UPDATE SALES SET AMOUNT_SOLD = sales_tbl(i).amount_sold WHERE PROD_ID = sales_tbl(i).prod_id AND CUST_ID = sales_tbl(i).cust_id AND TIME_ID = sales_tbl(i).time_id AND CHANNEL_ID = sales_tbl(i).channel_id AND PROMO_ID = sales_tbl(i).promo_id; EXIT WHEN sales_cur%notfound; END LOOP; CLOSE sales_cur; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE_APPLICATION_ERROR(-20001,'RAISE_APPLICATION_ERROR : ' SQLCODE ':' SUBSTR(SQLERRM,1,200)); END; / 108 2013 기술백서 White Paper

또다른난관 앞서소개한방법들의적용이가능하다면대량의 DML 작업에대한성능개선 Process 를가져갈 수있을것이다. 그러나또하나의극복해야할난관이아직기다리고있다. 이는 Partition Table 로의변경이필요한부분에해당하는것으로방대한양의데이터를저장하 고있는기존테이블을 Partition Table 로변경하는작업이만만치않다는것이다. 일정시간 Offline 이가능하다고하면변경작업을시도해볼수도있겠으나, 항상서비스가되어 야하는환경에서 Partition Table 로변경해야한다고권고한다면, 원론적으로는옳다고할수 있을지라도실무를담당하고있는 DBA 에게는큰당혹감만을안겨주는결과를낳을수있다. 하지만이어려워보이는문제도극복할수있는방법이있다. 이는바로 Partition Exchange( 이하 PE) 기능을이용하는것이다. PE 기능은말그대로일반테이블을 Partition Table 로의변경이가능함을의미한다. 또한, 추가적인공간도필요없어상당히효율적인방법으로 Partition Table 로의전환을이룰수있다. 아래테스트는 PE 기능을활용하여일반테이블을 Partition Table 로의손쉬운전환이가능함 을증명해준다. 기존에사용하던일반테이블 : Partition_test2 : Delete 테스트의테이블생성스크립트와데이터입력스크립트참조 Partition Table 로전환할 Partition Table 생성 CREATE TABLE partition_test (TIME_ID DATE, DAY_NAME VARCHAR2(9), DAY_NUMBER_IN_WEEK NUMBER(1,0), DAY_NUMBER_IN_MONTH NUMBER(2,0), CALENDAR_WEEK_NUMBER NUMBER(2,0), FISCAL_WEEK_NUMBER NUMBER(2,0), WEEK_ENDING_DAY DATE, WEEK_ENDING_DAY_ID NUMBER, CALENDAR_MONTH_NUMBER NUMBER(2,0), FISCAL_MONTH_NUMBER NUMBER(2,0), CALENDAR_MONTH_DESC VARCHAR2(8), Part 1 ORACLE 109

CALENDAR_MONTH_ID NUMBER, FISCAL_MONTH_DESC VARCHAR2(8), FISCAL_MONTH_ID NUMBER, DAYS_IN_CAL_MONTH NUMBER, DAYS_IN_FIS_MONTH NUMBER, END_OF_CAL_MONTH DATE, END_OF_FIS_MONTH DATE, CALENDAR_MONTH_NAME VARCHAR2(9), FISCAL_MONTH_NAME VARCHAR2(9), CALENDAR_QUARTER_DESC CHAR(7), CALENDAR_QUARTER_ID NUMBER, FISCAL_QUARTER_DESC CHAR(7), FISCAL_QUARTER_ID NUMBER, DAYS_IN_CAL_QUARTER NUMBER, DAYS_IN_FIS_QUARTER NUMBER, END_OF_CAL_QUARTER DATE, END_OF_FIS_QUARTER DATE, CALENDAR_QUARTER_NUMBER NUMBER(1,0), FISCAL_QUARTER_NUMBER NUMBER(1,0), CALENDAR_YEAR NUMBER(4,0), CALENDAR_YEAR_ID NUMBER, FISCAL_YEAR NUMBER(4,0), FISCAL_YEAR_ID NUMBER, DAYS_IN_CAL_YEAR NUMBER, DAYS_IN_FIS_YEAR NUMBER, END_OF_CAL_YEAR DATE, END_OF_FIS_YEAR DATE ) PARTITION BY RANGE( time_id )( PARTITION part1 VALUES less than (to_date('2002-12-31','yyyy-mm-dd')) ); -- Partiton Table 로전환될테이블의 Max 값을입력 Partition Exchange 수행 SQL> ALTER TABLE partition_test exchange partition part1 WITH TABLE partition_test2 without validation ; 테이블이변경되었습니다. 경과 : 00:00:00.03 기존테이블삭제후 Rename 110 2013 기술백서 White Paper

SQL> DROP TABLE partition_test2; 테이블이삭제되었습니다. 경과 : 00:00:00.06 SQL> RENAME partition_test to partition_test2; 테이블이름이변경되었습니다. 경과 : 00:00:00.03 위와같이수행하면기존의테이블은간단히 Partition Table 로변경할수있음을알수있다. 다 만주의할점은기존일반테이블에서가지고있던제약조건 (Primary Key) 이나 Index 구성은 모두동일하게생성하여야정상적인 PE 수행이가능하다. 결론 앞서소개한대량의 DML 작업의성능을개선하는방법은테이블의구조자체를변경하거나발생가능한 redo 의양을최대한감소시키는방법그리고 Index 의구조변경과 Drop 등으로정리할수있다. 하지만이러한방법은자칫실무를담당하는 DBA 에게는그저뜬구름잡는이야기에불과할수있다. 머리로는충분히이해하고공감할수있는좋은방법을제시하였다하더라도현실에적용할수없다면그공허함은더큰무게로다가올것이다. 하지만위에소개한내용들은실질적으로적용할수있고또한적용한사례가있다. 물론업무의 성격에따라수학공식처럼항상같은방식으로대입하여적용할수있는것은아니지만, 그환 경에맞는솔루션은항상존재한다고믿는다. 비현실적이라고치부해버리는순간성능개선의여지는요원해진다. 위의내용들의핵심을잘정 리하고있다면해당하는상황에대해여러가지성능개선아이디어를제시할수있고, 그중가장 손쉽게적용할수있는방법을협의를통해찾을수있을것이다. 대량의 DML 작업성능개선과시스템의 Down Time 최소화라는두마리토끼를잡는것은것은 어렵지만은않다. Part 1 ORACLE 111