SQL 힌트의 사용 방법 |
● DBA는 특정데이터에 대하여 optimizer가 알 수 없는 정보를 가질 수 있음. ● DBA는 optimizer보다 더 좋은 execution plan을 선택할 수 있음. ● DBA는 힌트를 사용하여 강제적으로 사용자가 선택한 execution plan을 생성하도록 optimizer에게 지시가능. |
∮힌트의 사용 |
● 힌트의 사용범위 ― SQL문을 위한 Optimization approach― SQL문에 대한 Cost-based approach의 goal(best throughput, best response time)― SQL문에 의해 접근되는 table에 대한 access path― join문에 대한 join순서 ― join문을 처리하기 위한 join operation
|
● Statement Block
― 간단한 SELECT , UPDATE, DELETE SQL문 · UNION operator에 의해 조합된 두 개의 component query로 구성한 한 compound query는 두 개의 SQL문 block을 가짐. (각 component query를 위해 하나의 SQL문 block이 생김.) |
● 힌트를 포함하는
Syntax ·DELETE,
·+ : 오라클이 그 comment를 해석할 수 있게 해주는 기능을합니다. 이 ‘ + ‘는 comment 표시후에 빈칸(blank)이 없이 즉시 따라와야만 합니다.
·힌트 : 이절에서언급되는 힌트중의 하나입니다. 만약 comment가 여러 힌트를 가진다면그 힌트들은 최소한 하나의 공간으로서 분리되어 있어야만 합니다.
·text : 힌트에 대한 설명 |
● 힌트를 무시하는 경우 ― 힌트가 쓰인 comment가 DELETE, SELECT , UPDATE 키워드 뒤에 오지 않고, 다른 곳에 쓰여 있는경우 ― 힌트가 Syntax error를 가진 경우 (동일한 comment내에 error를 가지지 않고 올바로 표현된 다른 힌트들은 인정) ― 충돌한 힌트의 조합들은 무시(한 comment내에 두 개 이상의 힌트가 있을 경우, Optimizer가 어떤 힌트를 먼저 써야하는지 모르는 경우)(동일한 comment내에 충돌한 힌트외에 다른 힌트는 인정.) · 오라클은 SQL*Forms Version 3 Trigger 와 같은 PL/SQL Version 1 을 사용하는 환경에서는모든 SQL 문에 있는 힌트들을 무시.· Optimizer는 cost-based approach를 사용하는 경우에 힌트를인식. · 한 SQL문 block에 RULE 힌트를 제외한 어떤 힌트들이 포함되어 있으면, optimizer 는 자동적으로 cost-based approach를 사용. |
옵티마이저를 위한 힌트와 사용 목표 |
― 힌트는 cost-based approach와 rule-based optimization approach 중에 하나를 선택
― cost-based approach를 선택한 경우에는 best throughput와 best reponse time사이에 하나를 선택 ― SQL문이 optimization approach 와 goal을 기술한 한개의 힌트를 가진다면, optimizer는 statistics의 존재여부와 ALTER SESSSION명령에 있는 OPTIMIZER_GOAL와 OPIMIZER_MODE 초기 파라메타의 값과는 상관없이 기술된 approach를 사용. |
∮ ALL_ROWS |
― ALL_ROWS 힌트는 best throughput(minimum total resource consumption)을 목적으로 SQL문 block을 최적화하기 위해 cost-based approach를 선택 ― optimizer는 best throughput을 목적으로 SQL문를 최적화 SELECT /*+ ALL_ROWS */ empno, ename, sal, job FROM emp WHERE empno = 566; |
∮ FIRST_ROWS |
― FIRST_ROWS 힌트는 best response time을 목적으로 SQL문 block을 최적화하기 위해 cost-based approach를 선택.(minimum resource usage to return first row) ― 이 힌트는 아래 내용을 이행할 수 있는 optimizer를 생성 · Index scan을 쓸수 있다면, optimizer는 full table scan보다는 Index scan을 사용. · Index scan을 쓸수 있다면, optimizer는 연관된 table이 nested loop의 inner table일 때마다, sort-merge join보다는 nested loops join을 선택. · Index scan이 ORDER BY절에 의해 쓰여지면, optimizer는 sort operation을 피하기 위해 index scan을 선택. ― optimizer는 best response time을 목적으로 아래 SQL문를 최적화 SELECT /*+ FIRST_ROWS */ empno, ename, sal, job FROM emp WHERE empno = 566; ― Optimizer는 아래 Syntax를 가지는 DELETE와 UPDATE SQL문 blocks과SELECT SQL문 block 에 있는 힌트는 무시.· set operators(UNION, INTERSECT, MINUS, UNION ALL) · GROUP BY절·FOR UPDATE 절·group functions·DISTINCT operator ― 이들 SQL문는 best response를 목적으로 최적화될 수 없습니다. ― 위의 경우 첫 번째 row를 반환하기 전에 SQL문에 접근되는 모든 행들을 retrieve해야만함. ― 이런 SQL문에 대해 힌트를 쓰면 optimizer는 cost-based approach를 사용하고, best throughput을 목적으로 최적화. ― SQL문에 ALL_ROWS나 FIRST_ROWS 힌트를 기술하고, data dictionary가 그 SQL문에의해 접근되는 table에 대해 어떤 statistics도 포함하지 않는다면, optimizer는 내부적으로 execution plan을 선택하고, missing statistics를 추정할 default statistics 값을 사용. ― 이 추정치(estimates)는 ANALYZE명령에 의해 생성되어진 것만큼 정확하지는 않음. ― ANALYZE명령을 사용하여 Cost-based optimization을 사용하는 SQL문에 의해 접근되는모든 table에 대한 statistics를 생성해야 함. ― Access path를 위한 힌트 또는 ALL_ROWS나 FIRST_ROWS 힌트를 가지는 join operation을 기술합니다면, optimizer는 힌트에 의해 기술된 join operation들과 access paths를 우선적으로 취함. |
실행 순서 방법을 위한 SQL 힌트 |
― 각 힌트들은 table에 대한 access method를 제안 ― 힌트중의 하나를 기술하는 것은 access path가 index 나 클러스터와 SQL문의 의미구조의존재를 기본적으로 이용할수 있다면 기술된 access path를 선택 ― 힌트가 access path를 이용할수 없다면 optimizer는 그것을 무시. ― SQL문에서 정확하게 access되는 table을 기술 ― SQL문이 table에 대한 alias를 사용하면, 힌트에서 table의 이름보다는 alias를 사용. ― table의 이름이나 alias 는 local database에 있는 한 table에 대한 하나의 synonym이나하나의 table을 의미함. |
∮ FULL |
― FULL 힌트는 table에 대해 full table scan을 선택 ― FULL 힌트의 문법은 FULL(table) ― (table)에는 full table scan을 수행하는 table의 alias나 name을 기술합니다. ― 예 : ACCOUNT table에 WHERE절의 조건에 의해 사용가능한 ACCNO 칼럼에 대한 index가있음에도 불구하고, 오라클은 이 SQL 문을 실행할 ACCOUNTS table에 full table scan을 수행. SELECT /*+ FULL(a) Don’t use the index on ACCNO */ accno, bal FROM accounts a WHERE accno = 7086854;■ NOTE· ACCONTStable이 alias A를 가지기 때문에 힌트는 table의 이름이 아닌 alias로 table을표현.· FROM 절에 table의 이름이 기술되었음에도 불구하고, 힌트에서 는 schema names을 기술하지 않는다. |
∮ROWID |
― ROWID힌트는 table에대해 ROWID에의한 table scan을선택 ― ROWID 힌트의문법은ROWID(table) ― (table)에는 ROWID에의한 table scan이이행되어지는 table의 alias나이름을기술. |
∮CLUSTER |
― CLUSTER힌트는 table에대해 cluster scan을선택 ― CLUSTER 힌트의문법은CLUSTER(table) ― (table)에는 cluster scan에의해접근되는 table의이름이나 alias를기술.SELECT –+ CLUSTER emp, ename, deptnoFROM emp, deptWHERE deptno = 10 AND emp.deptno = dept.deptno; |
∮HASH |
― HASH힌트는 table에대해 HASH scan을선택 ― HASH 힌트의문법은 HASH(table) ― (table)에는 hash scan에의해접근되는 table의이름이나 alias를기술 |
∮INDEX |
― INDEX힌트는 table에대해 index scan을선택
― INDEX 힌트의문법은 table : scan될 index와관련있는 table의이름이나 alias를기술 index : index scan이수행될 index를기술 ― 힌트는하나이상의 indexes들을기술 SELECT name, height, weightFROM patientsWHERE sex=’M’· sex의열은 index되어있고, 이칼럼은 ‘M’과 ‘F’의값을가짐.· 병원에남자의수와여자의수가동일하다면, 이질의는연관된 table의행의최다퍼센트를반환하고, full table scan이 index scan보다는더빠르게됩니다.· 병원의환자중남자의비율이매우적다면, 질의는관련된 table의행에대해적은비율을반환하고, 이경우에는 index scan이 full table scan보다더빠릅니다. SELECT /*+ INDEX(patients sex_index) Use SEX_INDEX, since there are few male patients */name, height, weightFROM patientsWHERE sex = ‘M’; |
∮FULL 힌트와 INDEX 힌트의비교예제 |
― 1. EMPtable의총건수는 10,000건, DEPTtable의총건수는 2400건. ― 2. EMPtable에서 empno, ename, sal을 SELECT ― 3. WHERE절의조건은 JOB 필드의 ‘SALESMAN’값을검사 ― 4. JOB_INDEX존재. ― 5. JOB필드에는 2개의값이존재(MANAGER-(9,751건/10,000건), SALESMAN-(249건/10,000건))· EMP, DEPT table을ANALYZE함.· sql_trace를 true로· OPTIMIZER_GOAL 은ALL_ROWS로 ― 예제 1analyze table emp estimate statistics;analyze table dept estimate statistics;alter session set sql_trace = true;alter session set optimizer_goal = all_rows;SELECT empno, ename, salfrom empwhere job = ‘SALESMAN’;SELECT /*+ full(emp) */ empno, ename, salfrom empwhere job = ‘SALESMAN’; SELECT /*+ index(emp job_index) */ empno, ename, salfrom empwhere job = ‘SALESMAN’; · OPTIMIZER_GOAL 은FIRST_ROWS로 SELECT /*+ full(emp) */ empno, ename, salfrom empwhere job = ‘SALESMAN’; SELECT /*+ index(emp job_index) */ empno, ename, salfrom empwhere job = ‘SALESMAN’; |
∮ INDEX_ASC |
― INDEX_ASC힌트는 table에대한 index scan을선택 ― 이 SQL문이 index range scan을사용합니다면, Oracle은 index된값들을오름차순으로정렬한 index entry들을 scan. ― INDEX_ASC 힌트의문법은 ― 각파라메타는 INDEX 힌트에서와같은목적을의미. ― range scan에대해서오라클의 default behavior는 index된값에대해오름차순으로정렬하고그 index entry들을 scan하는것이므로이힌트는일반적으로 index 힌트보다더나은점은없습니다. |
∮ INDEX_DESC |
― INDEX_DESC힌트는 table에대해 index scan을선택
― 만약 SQL 문이 index range scan을사용합니다면, 오라클은 index된값들을내림차순으로정렬한 index entry들을 scan. ― INDEX_desc 힌트의문법은
― 각파라메타는 INDEX 힌트에서와같은목적을의미. CREATE TABLE tank_readings (time DATE CONSTAINT un_time UNIQUE,temperature NUMBER); ― table의각행들은한시점에서시간과온도를저장.
FROM tank_readingsWEHRE time <= TO_DATE(:t) );
― 위 SQL문에대한 execution plan은아래그림과같습니다.
― 위 SQL문장을실행시키면, 오라클은아래와같은 operations를실행.
· step 4와 3은 subquery를실행. – step 4는시간 T와같거나더적은모든 TIME 값들을반환할 UN_TIME index의 range scan을수행. – step 3는 step 4로부터최대 TIME값을선택하고그값을반환. ·step 2 와 1은 parent query를실행. – step 2는 step 3에의해반환된 TIME 값에맞는 UN_TIME index의 unique scan을수행하고관련된 ROWID를반환. – step 1은 step 2에의해반환된 ROWID를사용하여 TANK_READING table을접근하고 TEMPERATURE 값을반환.
― Step 4에서오라클은오름차순으로정렬된 index에있는 TIME 값을 scan.
― 이것의 execution plan을아래그림과같습니다.
· step 3은 T와동일하거나더적은 TIME값을찾기위해 UN_TIME index를 range scan하고그와관련된 ROWID를반환. ― INDEX_DESC 힌트때문에 step 3은 T값부터시작하는내림차순으로정렬된 index에서 TIME값을 scan. |
∮AND_EQUAL |
― AND_EQUAL힌트는몇몇의 single-column index에대한 scan을 merge하는 access path를사용하는 execution plan을선택 ― 이 AND_EQUAL 힌트의문법은 table : merge할 index와연관된 table의이름이나 alias를기술. index : index scan을수행하는 index를기술― 최소 2개이상최대 5개이하의 index를기술해야합니다. |
∮USE_CONCAT |
― USE_CONCAT 힌트는 OR 조건을 UNION ALL set operator를사용하는 compound query로변환 ― 이변환은 UNION ALL set operations을사용하는질의가이를사용하지않을때보다비용이더적을경우에만발생 |
조인순서를위한 SQL 힌트 |
ORDERED 힌트는 join order를제안 |
∮ORDERED |
― ORDERED 힌트는 FROM절에 table이나타나는순서대로 table을 join시킨다. ― 예를들어, 아래 SQL문은 table TAB1과 table TAB2를조인한후에그결과와 table TAB3을조인합니다. SELECT /*+ ORDERED */ tab1.col1, tab2.col2, tab3.col3FROM tab1, tab2, tab3WHERE tab1.col1 = tab2.col1 AND tab2.col1 = tab3.col1; ― SQL문에서 ORDERED 힌트를생략하고 join를수행하면, optimizer가 table을 join할순서를선택 ― 각 table에서 SELECT 해오는행의수에대해알고있다면 join 순서를기술하는 ORDERED 힌트를사용하는것이좋다. ― 사용자가 inner 와 outer table을선택하는것이 optimizer가할수있는것보다나을수도있습니다. |
Table 조인방법 SQL 힌트 |
● SQL문에서나타나는조인된 table을정확하게기술해야만합니다.
● SQL문이 table의 alias를사용합니다면힌트에서도 table의이름보다는 alias를사용해야만합니다. ● table의이름이나 alias는 local database에 table의 synonym이나 table을가지고있어야만합니다. ● USE_NL과 USE_MERGE 힌트는 ORDERED 힌트를사용해야만합니다. ● 오라클은참조된 table이조인에서강제로 innertable이될때이힌트를사용해야만합니다. ● 참조된 table이 outer table이라면이힌트들을무시합니다. |
∮USE_NL |
― USE_NL 힌트는 table을적는부분에 table 기술된 table은 inner table로서사용하여 nested loops로서다른 table의 row source와기술된 table을 join하게합니다. ― USE_NL 힌트의문법은
table : nested loops join의 inner table로서사용될 table의이름과 alias입니다. ― 예를들어서, ACCOUNTS와 CUSTOMERS table을조인하는 SQL문이있다고생각해보자. 이들 table들은 cluster에함께저장되지않았다고가정합니다. SELECT accounts.balance, customers.last_name, customers.first_nameFROM accounts, customersWHERE accounts.custno = customers.custo; ― cost-based approach의 default 목적은 best throughput이므로이 optimizer는좀더빨리질의에의해 SELECT 된모든행들을반환하기위해 nested loops operation이나 sort-merge operation중하나를선택합니다.
― 많은경우에 nested loops join은 sort-merge join보다는더빨리첫번째행을반환합니다. |
∮USE_MERGE |
― USE_MERGE 힌트는오라클이 sort-merge join으로각 table을조인하게끔하는방법입니다. ― USE_MERGE 힌트의문법은 |
병렬쿼리실행을위한 SQL 힌트 |
∮CACHE |
― CACHE 힌트는 full table scan이수행됐을때힌트에있는 table에대해 retrieve된블록들은버퍼캐시에있는 LRU list의가장최근(most recently)에사용되어진것의끝에위치 ― 이 option은 small lookup table에유용하다. CACHE 힌트는 table의 default caching specification을무시 SELECT /*+ FULL (scoot_emp) CACHE(scott_emp) */ enameFROM scott.emp scott_emp; |
∮NOCACHE |
― NOCACHE 힌트는 full table scan이수행됐을때힌트에있는 table에대해 retrieve된블록들은버퍼캐시에있는 LRU list의가장오래전(least recently)에사용되어진것의끝에위치 ― 버퍼캐수에 blocks의일반적인행동 SELECT /*+ FULL (scoot_emp) NOCACHE(scott_emp) */ enameFROM scott.emp scott_emp; |
구문연계를고려하는 SQL 힌트 |
● SQL이융통성이있는언어이기때문에하나이상의 SQL문이 Application을필요로할것입니다. ● 2개의 SQL문이동일한결과를산출함에도불구하고, 오라클은 2중의하나가더처리속도가빠릅니다. ● execution plans을비교하기위해 EXPLAIN PLAN SQL문의결과와두 SQL문의비용들을사용할수있습니다. |
∮두 SQL문에대한 execution plan 비교 |
● 첫번째 SQL문과그것에대한 execution plan
SELECT dname, deptnoFROM deptWHERE deptno NOT IN( SELECT deptno FROM emp);
― Execution Plan with Two Full Table Scans
― step3을통해오라클은 DEPTNO 칼럼에 index가있음에도불구하고 EMPtable을 full table scan함으로서위 SQL문을실행합니다는것을알수있습니다.
― full table scan은time-consuming operation을할수있습니다.
― EMPtable을찾는subquery에 index사용이가능한 WHERE절이없기때문에오라클은 index를사용할수없습니다. ― 그러나, 아래의 SQL문은 index에접근함으로서동일한행을 SELECT 합니다.
SELECT dname, deptnoFROM deptWHERE NOT EXISTS(
SELECT deptnoFROM empWHERE dept.deptno = emp.deptno);
― Execution Plan with a Full Table Scan and an Index Scan ― subquery의 WHERE절이 EMPtable의 DEPTNO칼럼을사용하므로 DEPTNO_INDEX를사용할수있습니다. ― index의사용은 execution plan의 step3에서하게됩니다 ― DEPTNO_INDEX의 index range scan은첫번째문장에서 EMP table의 full scan하는것보다시간이더적게걸린다. ― 이런이유로두번째 SQL 문은첫번째보다는더빠릅니다. ― Application에 NOT IN operator를사용하는 SQL문를가진다면 NOT EXISTS operator를사용해서그것들을다시써라. 이것은 index가있다면그 index를사용할수있게해줄것입니다. |
기존 SQL문을튜닝하는방법 |
● 존재하는 application에서 SQL 문을튜닝하는것은새로운문장을기록하는것과는다른작업(task)입니다.
● 비록요구된지식이같을지라도프로세스는다르다. ● 튜닝하기위한 application에서특별한문장을다음과같이함으로써분리해야합니다. · application에익숙하라. ● 이전절에서논의했던새로운 SQL 문장을기록하고, index, 클러스터, 해싱, 힌트를 하기 위한지침을 이용하여문장을 튜닝 할 수 있습니다. |
∮Know the Application |
― application과 SQL 문장과 data에익숙해져야합니다. ― 만약당신이 application을설계하고개발하지않았다면그것을한사람에게의견을물어보라. ― application이하는것을기록하라. · application을이용하는 SQL 문은무엇인가? · application이처리하는데이타는무엇인가? · 데이타의특징과 distribution은무엇인가? · applicatin의무슨 operation이 data를실행하는가? ― application 사용자들과성능에대해이야기해보라. |
∮Use the SQl Trace Facility |
― 오라클은성능을측정하기위하여진단에도움이되는 tool을몇가지제공합니다 ― appllicatin을튜닝하는데특별히도움이되는 tool중에하나는 SQL trace 입니다. ― SQL trace facililty는오라클에의해처리된각 SQL 문장을위한통계를생성합니다. ― 통계는다음을나타낸다. · SQL 문장이파싱, 실행, 페치된횟수 |
∮Tuning Individual SQL statements |
― 사용중인사용자응용을수정하지않고 SQL문의변경된문법을탐색할수있음을명심하라. ― 사용자가존재하는 SQL문의비용과실행계획을비교하고고려하는문장을변경하는것은단순히 EXPLIAN PLAN을이용합니다. ― 만약사용자가 SQL문의 tune을위해새로운 index를생성하면사용자는 optimizer가응용이실행될때마다 index를사용할것인지를결정하기위해 EXPLAIN PLAN 명령을사용할수있습니다. ― 만약사용자가현재 parse된문장을 tune하기위해새로운 index를생성하면 Oracle은 SQL 문에서이 index를사용하지않는다. ― SQL 문장이다시실행되면 optimizer는자동적으로새로생성된 index를사용하기위해새로운실행계획을선택합니다. ― 만약사용자가분산 SQL 문을 tune 하기위해원격데이타베이스의 index를생성하면 optimizer는 SQL문이다시실행될때이 index를고려합니다. ― 또한사용자는 SQL 문장에대한실행계획이 optimizer 보다더효과적으로사용할수있도록 tune합니다는것을명심하라. ― 예를들어사용자가하나의 SQL문을사용하기위해 index를생성하면 optimizer는사용자의응용에서다른문장을실행하기위해그 index를선택합니다. |