SSISO Community

시소당

25가지 sql 작성법 (14~25)

14.  자신의  데이터를  알아라
내가  이미  설명한  것처럼,  당신은  당신의  데이터를  상세하게  알고  있어야  한다.예를  들어  당신이
BOXER라는  테이블을  가지고  있고  그  테이블이  유일하지  않은  인덱스를  가진  SEX라는  컬럼과
BOXER_NAME이라는  두  개의  테이블을  가지고  있다고  가정해  보자.  만약  그  테이블에  같은  수의
남자,  여자  복서가  있다면  오라클이  FULL  TABLE  SCAN을  수행하는  경우  다음의  질의가  훨씬  빠를
것이다.

SELECT  BOXER_NAME
FROM  BOXER
WHERE  SEX  =  'F';

당신은  다음과  같이  기술함으로써  질의가  FULL  TABLE  SCAN을  수행하는지를  확실하게  해둘수  있다.

SELECT  BOXER_NAME  --+  FULL
FROM  BOXER
WHERE  SEX  =  'F';

만약  테이블에  980  명의  남성  복서  데이터가  있다면,  질의는  인덱스  SCAN으로  끝나기  때문에
아래형식의  질의가  더  빠를  것이다.

SELECT  BOXER_NAME  --+  INDEX  (BOXER  BOXER_SEX)
FROM  BOXER
WHERE  SEX  =  'F';

이  예는  데이터의  분포에  대해  잘  알고  있는  것이  얼마나  중요한  가를  예시해  준다.  데이터가  많아지고(GROW)  데이터  분포가  변화하는  것처럼  SQL  도  매우  다양할  것이다.  오라클은  OPTIMIZER  가  테이블에  있는  데이터의  분포를  잘  인식하고  적절한  실행  계획을  선택하도록  하기  위해  오라클  7.3  에  HISTOGRAMS라는  기능을  추가했다.

15.  KNOW  WHEN  TO  USE  LARGE-TABLE  SCANS.
작거나  큰  테이블에서  행들을  추출할  때,  전체  테이블의  검색은  인텍스를  사용한  검색보다  성능이
더  좋을  수도  있다.  매우  큰  테이블의  인덱스  검색은  수많은  인덱스와  테이블  블록의  검색이  필요할
수도  있다.  이러한  블록들이  데이터베이  스  버퍼  캐쉬에  이동되면  가능한한  오래도록  그곳에  머무른
다.  그래서  이러한  블록들이  다른  질의등에  필요하지  않을  수도  있기  때문에,  데이터베이스  버퍼
히트  비율이  감소하며  다중  사용자  시스템의  성능도  저하되기도  한다.  그러나  전체  테이블  검색에
의해서  읽혀진  블록들은  데이터베이스  버퍼  캐쉬에서  일찍  제거가  되므로  데이터베이스  버퍼  캐쉬
히트  비율은  영향을  받지  않게  된다.

16.  MINIMIZE  TABLE  PASSES.
보통,  SQL질의시  참조하는  테이블의  숫자를  줄임으로  성능을  향상시킨다.  참조되는  테이블의  숫자
가  적을수록  질의는  빨라진다.  예를  들면  NAME,  STATUS,  PARENT_INCOME,  SELF_INCOME의  네개
의  컬럼으로  이루어진  학생  테이블  에서  부모님에  의존하는  학생과  독립한  학생의  이름과  수입에
대해서  질의시,  이  학생  테이블을  두번  참조하여  질의하게  된다..
SELECT  NAME,  PARENT_INCOME
FROM  STUDENT
WHERE  STATUS  =  1
UNION
SELECT  NAME,  SELF_INCOME
FROM  STUDENT
WHERE  STATUS  =  0;
(  NAME이  프라이머리  키이며,  STATUS는  독립한  학생의  경우는  1,  부모님에  의존적인  학생은  0으로
표시한다)
위의  같은  결과를  테이블을  두번  참조하지  않고도  질의  할  수  있다.

SELECT  NAME,PARENT_INCOME*STATUS  +  SELF_INCOME(1-STATUS)
FROM  STUDENT;

17.  JOIN  TABLES  IN  THE  PROPER  ORDER.
다수의  테이블  조인시  테이블들의  조인되는  순서는  매우  중요하다.  전반적으로,  올바른  순서로  테이
블이  조인되었다면  적은  수의  행들이  질의시  참조된다.  언제나  다수의  조인된  테이블들을  질의시
우선  엄격하게  조사하여  행들의  숫자를  최대한으로  줄인다.  이러한  방법으로  옵티마이저는  조인의
차후  단계에서  적은  행들을  조사하게  된다.  뿐만  아니라,  여러  조인을  포함하는  LOOP  JOIN에서는
가장  먼저  참조되는  테이블(DRIVING  TABLE)이  행들을  최소한으로  리턴하도록  해야한다.  그리고,
마스터와  상세  테이블  조인시에는(예를  들면  ORDER  &  ORDER  LINE  ITEM  TABLES)  마스터  테이블
을  먼저  연결  시켜야  한다.  규칙에  근거한  옵티마이저의  경우에는  FROM  CLAUSE의  마지막  테이블
이  NESTED  LOOP  JOIN의  DRIVING  TABLE이  된다.  NESTED  LOOP  JOIN이  필요한  경우에는  LOOP
의  안쪽의  테이블에는  인텍스를  이용하는  것을  고려할  만하다.  EXPLAIN  PLAN과  TKPROF는  조인
타입,  조인  테이블  순서,  조인의  단계별  처리된  행들의  숫자들을  나타낸다.
비용에  근거한  옵티마이저의  경우에는  WHERE  CLAUSE에  보여지는  테이블의  순서는  옵티마이저가
가장  최적의  실행  계획을  찾으려고  하는  것과  상관  없다.  조인되는  테이블의  순서를  통제하기  위해
서  ORDERED  HINT를  사용하는  것이  낫다.

SELECT  ORDERS.CUSTID,  ORDERS.ORDERNO,
ORDER_LINE_ITEMS.PRODUCTNO  --+ORDERED
FROM  ORDERS,  ORDER_LINE_ITEMS
WHERE  ORDERS.ORDERNO  =  ORDER_LINE_ITEMS.ORDERNO;

18.  USE  INDEX-ONLY  SEARCHES  WHEN  POSSIBLE.
가능하다면,  인덱스만을  이용하여  질의를  사용하라.  옵티마이저는  오직  인덱스만을  찾을  것이다.
옵티마이저는  SQL을  만족시키는  모든  정보를  인덱스에서  찾을수  있을때,인덱스만을  이용할  것이다.
예를들면,  EMP테이블이  LANME과  FNAME의  열에  복합  인덱스를  가지고  있다면  다음의  질의는
인덱스만은  이용할  것이다.

SELECT  FNAME
FROM  EMP
WHERE  LNAME  =  'SMITH';

반면에  다음의  질의는  인덱스와  테이블을  모두  참조한다.

SELECT  FNAME  ,  SALARY
FROM  EMP
WHERE  LNAME  =  'SMITH';

19.  REDUNDANCY  IS  GOOD.

WHERE  CLAUSE에  가능한한  많은  정보를  제공하라.  예를  들면  WHERE  COL1  =  COL2  AND  COL1  =  10
이라면  옵티마이저는  COL2=10이라고  추론하지만,  WHERE  COL1  =  COL2  AND  COL2  =  COL3이면
COL1=COL3이라고  초론하지는  않는다.

20.  KEEP  IT  SIMPLE,  STUPID.
가능하면  SQL문을  간단하게  만들라.  매우  복잡한  SQL문은  옵티마이저를  무력화시킬  수도  있다.
때로는  다수의  간단한  SQL문이  단일의  복잡한  SQL문보다  성능이  좋을  수도  있다.
오라클의  비용에  근거한  옵티마이저는  아직은  완벽하지않다.  그래서  EXPLAIN  PLAN에  주의를
기울여야  한다.  여기서  비용이란  상대적인  개념이기에  정확히  그것이  무엇을  의미하는지  알지
목한다.  하지만  분명한  것은  적은  비용이  보다  좋은  성능을  의미한다는  것이다.
종종  임시  테이블을  사용하여  많은  테이블들을  포함하는  복잡한  SQL  조인을  쪼개는  것이  효율적일
수도  있다.  예를  들면,  조인이  대량의  데이터가  있는  8개의  테이블을  포함할  때,  복잡한  SQL을  두
세개의  SQL로  쪼개는  것이  낫을  수  있다.  각각의  질의는  많아야  네개정도의  테이블들을  포함하며
중간  값을  저장  하는  것이  낫을  수  있다.

21.  YOU  CAN  REACH  THE  SAME  DESTINATION  IN  DIFFERENT  WAYS.
많은  경우에,  하나  이상의  SQL문은  의도한  같은  결과를  줄  수  있다.  각각의  SQL은  다른  접근  경로
를  사용하며  다르게  수행한다.  예를들면,  MINUS(-)  산술자는  WHERE  NOT  IN  (SELECT  )  OR
ERE  NOT  EXISTS  보다  더  빠르다.
예를들면,  STATE와  AREA_CODE에  각각  다른  인덱스가  걸려  있다.  인덱스에도  불구하고  다음의  질의
는  NOT  IN의  사용으로  인해  테이블  전체를  조사하게된다.
SELECT  CUSTOMER_ID
FROM  CUSTOMERS
WHERE  STATE  IN  ('VA',  'DC',  'MD')
AND  AREA_CODE  NOT  IN  (804,  410);

그러나  같은  질의가  다음  처럼  쓰여진다면  인덱스를  사용하게  된다
SELECT  CUSTOMER_ID
FROM  CUSTOMERS
WHERE  STATE  IN  ('VA',  'DC',  'MD')
MINUS
SELECT  CUSTOMER_ID
FROM  CUSTOMERS
WHERE  AREA_CODE  IN  (804,  410);

WHERE절에  OR을  포함한다면  OR대신에  UNION을  사용할  수  있다.  그래서,  SQL  질의를  수행하기
전에  먼저  실행계획을  조심스럽게  평가해야  한다.  이러한  평가는  EXPLAIN  PLAN  AND  TKPROF를  이
용하여  할  수  있다.

22.  USE  THE  SPECIAL  COLUMNS.
ROWID  AND  ROWNUM  열을  이용하라.  ROWID를  이용하는  것이  가장  빠르다.
예를들면,  ROWID를  이용한  UPDATE는  다음과  같다.

SELECT  ROWID,  SALARY
INTO  TEMP_ROWID,  TEMP_SALARY
FROM  EMPLOYEE;

UPDATE  EMPLOYEE
SET  SALARY  =  TEMP_SALARY  *  1.5
WHERE  ROWID  =  TEMP_ROWID;

ROWID값은  데이터베이스에서  언제나  같지는  않다.  그래서,  SQL이나  응용  프로그램이용시  ROWID값
을  절대화  시키지  말라.  리턴되는  행들의  숫자를  제한  시키기위해  ROWNUM을  이용하라.  만약에  리턴
되는  행들을  정확히  모른다면  리턴되는  행들의  숫자를  제한하기위해  ROWNUM을  사용하라
다음의  질의는  100개  이상의  행들을  리턴하지는  않는다.
SELECT  EMPLOYE.SS#,  DEPARTMENT.DEPT_NAME
FROM  EMPLOYEE,  DEPENDENT
WHERE  EMPLOYEE.DEPT_ID  =  DEPARTMENT.DEPT_ID
AND  ROWNUM  <  100;

23.함축적인  커서대신  명시적인  커서를  사용하라.
함축적  커서는  여분의  FETCH를  발생시킨다.  명시적  커서는  DECLARE,  OPEN,  FETCH와  CLOSE
CURSOR문을  사용하여  개발자에  의해서  생성된다.  함축  커서는  DELETE,  UPDATE,  INSERT와
SELECT문을  사용하면  오라클에  의해서  생성된다.

24.오라클  병렬  쿼리  옵션을  찾아서  이용하라.
병렬  쿼리  옵션을  사용하면,  보다  빠른  성능으로  SQL을  병렬로  실행할  수  있다.
오라클  7에서는,  오직  FULL  TABLE  SCAN에  기반한  쿼리만이  병렬로  수행될  수  있다.
오라클  8에서는,  인덱스가  분할되어있다면  INDEXED  RANGE  SCANS에  기반한  쿼리도  병렬로  처리될
수  있다.  병렬  쿼리  옵션은  다수의  디스크  드라이버를  포함하는  SMP와  MPP  SYSTEM에서만  사용될
수  있다.

오라클  서버는  많은  우수한  특성을  가지고  있지만,  이러한  특성의  존재만으로는  빠른  성능을  보장하
지  않는다.  이러한  특성을  위해서  데이터베이스를  조정해야하며  특성을  이용하기  위해  특별하게  SQL
을  작성해야  한다.  예를  들면,  다음의  SQL은  병렬로  수행될  수  있다.

SELECT  *  --+PARALLEL(ORDERS,6)
FROM  ORDERS;

25.네트웍  소통량을  줄이고  한번에  처리되는  작업량을  늘려라.
ARRAY  PROCESSING과  PL/SQL  BLOCK을  사용하면  보다  나은  성능을  얻을  수  있고  네트웍  소통량을
줄인다.  ARRAY  PROCESSING은  하나의  SQL문으로  많은  ROW를  처리할  수  있게  한다.  예를  들면,
INSERT문에서  배열을  사용하면  테이블내의  1,000  ROW를  삽입할  수  있다.  이러한  기술을  사용하면
주요한  성능  향상을  클라이언트/서버와  배치시스템에서  얻어질  수  있다.

복합  SQL문은  과도한  네트웍  소통을  유발할  수  있다.  그러나  만일  SQL문이  단일  PL/SQL  블록안에
있다면,  전체  블록은  오라클  서버에  보내져서  그곳에서  수행되고,  결과는  클라이언트의
APPLICATION에게  돌아온다.

개발자와  사용자는  종종  SQL을  데이터베이스에서  데이터를  검색하고  전송하는  간단한  방법으로  사용
한다.  때때로  직접적으로  SQL을  작성하지  않고  코드  발생기를  사용하여  작성한  APPLICATION은  심
각한  성능  문제를  일으킨다.  이러한  성능감퇴는  데이터베이스가  커지면서  증가한다.

SQL은  유연하기  때문에,  다양한  SQL문으로  같은  결과를  얻을  수  있다.  그러나  어떤  문은  다른  것보
다  더  효율적이다.  여기에  기술된  팁과  기법을  사용하면  빠르게  사용자에게  정보를  제공할  수  있는
APPLICATION과  리포트를  얻을  수  있다.  

출처  :  http://www.ibm.com//developerworks/kr/forums/dw_thread.jsp?forum=7&thread=855&cat=4

1291 view

4.0 stars