Laboratory/MSSQL

SQL튜닝기본 과정 요약 DB 튜닝

theking 2007. 8. 28. 18:31

1.최대값 구하기

최적화- select/*+ index_desc(board board_x1) */NVL(SEQ,0)+1

         from BOARD

         where bbs_gb='AA' and ROWNUM = 1;

 

 차선책- select NVL(MAX(SEQ),0) + 1

          from BOARD

          where bbs_gb='AA';

          

 

2.그룹함수를 사용하거나DECODE함수를 사용할 때 불필요하게NVL함수를 사용하지 않기.

최적화- selectNVL(SUM(DECODE(HOMETEAM_ID, 'K07', HOME_SCORE)),0)

from SCHEDULE_T

            where gubun='S'

            and (hometeam_id = 'K07' or awayteam_id= 'K07');

         

설명 - SUM할 때 널은 빼고 계산해서 굳이 안에서 널체크를 할 필요는 없다.

           그러나 경기가 하나도 없었거나 자료가 하나도 없을때 널이 출력되는 것을 막기 위해

           제일 바깥쪽 널체크는 필요하다.

         

3. unionunion all을 비교

  (union은 두sql문의 결과를 합칠 때앞에 있는 컬럼순으로 자료를sort,

   union allsql문의 결과를sort하지 않고윗 부분sql문의 결과와 아래sql문의 결과를+)

 

  select, sum(총득점) as총득점, sum(총실점) as총실점

  from (

       select awayteam_id, nvl(sum(home_score), 0)총득점,

               nvl(sum(away_score), 0)총실점

       from schedule_t

       where gubun='S'

       and hometeam_id = 'K07'

       group by awayteam_id         

       union

       select hometeam_id, nvl(sum(away_score), 0)총득점,

               nvl(sum(home_score), 0)총실점

       from schedule_t

       where gubun='S'

       and awayteam_id = 'K07'

       group by hometeam_id                 

       )

  group by;       

  

  설명-이와 같이 했을때는 각각group함수sum을 사용하여서자료를sort한 후

         union으로 인해sql문의 결과를select문에 나열된 컬럼순으로sort(sort unique)

         그 결과를 가지고group함수sum을 위해 자료를sort.

 

  select, sum(총득점) as총득점, sum(총실점) as총실점

  from (

       select awayteam_id, nvl(sum(home_score), 0)총득점,

               nvl(sum(away_score), 0)총실점

       from schedule_t

       where gubun='S'

       and hometeam_id = 'K07'

       group by awayteam_id         

       union all

       select hometeam_id, nvl(sum(away_score), 0)총득점,

               nvl(sum(home_score), 0)총실점

       from schedule_t

       where gubun='S'

       and awayteam_id = 'K07'

       group by hometeam_id                 

       )

  group by;       

  

  설명-이와 같이 했을때는 각각group함수sum을 사용하여서 자료를sort한 후

union all으로 인해 두sql문의 결과를 합친후 그 결과를 가지고group함수sum

위해 자료를sort.

        

 

4.업데이트 할 때 실수하기 쉬운 점(널의update)

 

  1.문제sql         

  

     update emp x

     set sal = (SELECT NVL(x.sal, 0) +NVL(y.sal, 0)

                FROM bonus y

                WHERE x.ename = y.ename);

                

.설명-bonus테이블에 데이타가 없으면NVL(y.sal, 0)이 널이 되어서 결국상수+ NULL

형태가 되어서널로UPDATE된다.            

  

  2.해결책1(where에서 체크하기).

     update emp x

     set sal = (SELECT NVL(x.sal, 0) + NVL(y.sal, 0)

                FROM bonus y

                WHERE x.ename = y.ename)

     where exists (select 1

                   from bonus z

                   where x.ename = z.ename)

                   

    .설명-널을 막기 위해where조건에서 보너스에사원의 이름이 있는지 확인하여없으면

             update안한다.

    

                   

3.해결책2(그룹함수를 사용하기)

(그룹함수는 자료가 존재하지 않더라고 항상 하나의 값(null포함)을 리턴)

  

     update emp x

     set sal = (SELECT NVL(x.sal, 0) + NVL(min(y.sal), 0)

                FROM bonus y

                WHERE x.ename = y.ename);

    

    .설명-그룹함수를 사용하여보너스에 해당사원이름이 없더라도NVL(min(y.sal), 0)0

            되므로 결국상수+ 0의 형태가 되어결과값은 항상상수가 된다.

 

 

 

5.인덱스의 사용-변형(suppressing),사용:해당조회조건의 컬럼에 인덱스가 있다는 가정하에 설명.

  1)인덱스를 사용하지 않는 경우

     ♣ 인덱스 컬럼에 변형이 가해지는 경우

       (연산된 값을 비교하기 위해서는컬럼을 변형하기보다조건값(상수)를 변형해야 한다.)

       

       1)

       SELECT player_name, team_id, birth

       FROM player_t

       WHEREto_char(birth, 'yyyymmdd')between '19690101' and '19691231'

       

       위의sql문은 조건컬럼을 변형시켜서 테이블을full scan하게 된다.

       위의sql문을 아래와 같이 변경.

       

       SELECT player_name, team_id, birth

       FROM player_t

       WHERE birth betweento_date('19690101', 'yyyymmdd') and

to_date('19691231', 'yyyymmdd')

 

       2)

       SELECT player_name, team_id, back_no

       FROM player_t

       WHEREsubstr(player_name, 1, 1)= '' -> full scan

       ORDER BY team_id;

 

       아래와 같이 변경.

               

       SELECT player_name, team_id, back_no

       FROM player_t

       WHEREplayer_name like '%'-> index range scan

       ORDER BY team_id;

       

       기타 예)

       sal*12 > 3000000            --->>> sal > 3000000/12

       deptno || job = '10SALESMAN' --->>> deptno = '10' and job = 'SALESMAN'

       nvl(deptno) = '10'          --->>> deptno = '10'

 

 

 

NULL, NOT NULL비교를 하는 경우

       (인덱스를 구성하는컬럼값이NULL이면해당 레코드는인덱스대상에서 제외되기 때문에

        NULL값을 비교하는조건절의 컬럼에 인덱스가 있다고 해도인덱스 스캔을 하지 않는다.)

       

       1)

       SELECT player_name, team_id, nickname

       FROM player_t

       WHEREnickname IS NOT NULL;

       

       아래로 바꾼다.

 

       SELECT player_name, team_id, nickname

       FROM player_t

       WHEREnickname > ' ';

       

       2)

       SELECT player_name, team_id, height

       FROM player_t

       WHEREheight IS NOT NULL;

       

       아래로 바꾼다.

       

       SELECT player_name, team_id, height

       FROM player_t

       WHEREheight > 0;

       

NOT비교 검색을 하는 경우

  (긍정형으로 변경, NOT EXISTS사용하여 변경)

 

 1)

 SELECT player_name, team_id, position

 FROM player_t

 WHERE postion <> ‘MF’

 

 아래와 같이 바꿈.

 

SELECT player_name, team_id, position

 FROM player_t

 WHERE postion > ‘MF’ or postion < ‘MF’

 

 설명)

 하나씩 인덱스스캔을 하고 두 결과를concatenation한다.

 

 

 

2)인덱스를 사용하지 못하게 하는 경우

where절에 있는 조건 컬럼 모두에게 인덱스가 있는 경우 스캔하는 인덱스 변경.

 

1) 

SELECT player_name, team_id, position, height, nickname

FROM player_t

WHERE player_name LIKE ‘%’

AND postion = ‘DF’

 

위에서 옵티마이져는user_indexes, user_ind_columns를 사용하여 인덱스의 유무

확인한다.여기서는 옵티마이져는position의 인덱스를 사용하였으나 실제로는

postion = ‘DF’129명으로 많고player_name LIKE ‘%’6명이다.

그러므로player_name의 인덱스를 사용하는 것이 좋으므로 아래와 같이 바꾼다.

 

SELECT player_name, team_id, position, height, nickname

FROM player_t

WHERE player_name LIKE ‘%’

ANDRTRIM(postion)= ‘DF’

 

3)조회하는 컬럼을 모두 인덱스로 만들기

♣ 인덱스에WHERE절의 컬럼뿐만 아니라SELECT절의 모든 컬럼이 모두 인덱스

존재하면처리범위를 줄이고테이블을 랜덤액세스 하지 않고인덱스스캔만으로

원하는 자료를 구할 수 있다.

 

1)

SELECTstadium_id, SUM(home_score)

FROM schedule_t

WHEREgubun = ‘S’

GROUP BY stadium_id

 

인덱스를 다음과 같이 만들면 인덱스만 사용하여 값을 추출한다.

 

CREATE INDEX schedule_t_x1 ON schedule_t (

  gubun, stadium_id, home_score

);

 

  

 

4) NULL의 활용

♣ 컬럼의 특정값이 분포비율이 과다할 때

  SELECT y.team_name, count(*)

  FROM player_t x, team_t y

  WHERE nation = ‘대한민국

  AND x.team_id = y.team_id

  GROUP BY y.team_name

  ORDER BY y.team_name

 

 설명:대한민국인 선수가90%이상이므로인덱스 스캔하면서 테이블을 랜덤액세스하는 것

      보다TABLE FULL SCAN더 수행속도가빠르다.

 UPDATE player_t

 SET nation = NULL

 WHERE nation = ‘대한민국

 

 commit;

 

 ALTER INDEX player_t_x6 REBULID UNRECOVERABLE;

 

SELECT y.team_name, count(*)

FROM player_t x, team_t y

 WHERE nation IS NULL

 AND x.team_id = y.team_id

 GROUP BY y.team_name

 ORDER BY y.team_name

 

  

■ 조인

 ▶ 조인의 특성.

-조인순서와 관계없이 결과는 동일하나 조인순서에 따라 성능차이가 난다.

     -인덱스는 처리범위를 줄여 조인대상이 되는 자료의 범위를 줄이므로

       조인의 횟수를 감소 시킬 수 있다.

     -일반적 조인의 순서는 처리범위가 적은 테이블에서 많은 테이블 순으로 한다.

       (컬럼의 인덱스 유무,조회조건에 따라 달라진다.)

     -옵티마이져는 인덱스,조회조건 등에 따라 조인 순서 및 방법 결정.

 

1.    조인순서의 조정(랜덤액세스의 구분).

1)

개선전>>

select/*+ ordered */z.stadium_name, x.sche_date,

              x.hometeam_id, y.player_name, y.position

fromschedule_t x, player_t y, stadium_t z

where y.team_id = x.hometeam_id

and x.gubun = 'S'

and x.sche_date = '20020911'

and x.stadium_id = z.stadium_id

and y.position = 'GK'

 

SELECT STATEMENT Hint=CHOOSE

 NESTED LOOPS(19행에 아래를 유니크검색이므로19번의 랜덤액세스)

   NESTED LOOPS(인덱스범위검색,루프이므로4*42의 랜덤액세스.결과19)

     TABLE ACCESS BY INDEX ROWID    SCHEDULE_Tàx의 조회조건결과:4

       INDEX RANGE SCAN     SCHEDULE_T_PK

     TABLE ACCESS BY INDEX ROWID    PLAYER_T ày의 조회조건:42

       INDEX RANGE SCAN     PLAYER_T_X5

   TABLE ACCESS BY INDEX ROWID      STADIUM_T

     INDEX UNIQUE SCAN      STADIUM_T_PK

 

설명:schedule_t테이블을 인덱스 스캔할 때135행의 인덱스 검색 후경기일자

‘20020911’4행의 자료를 찾아낸다이것은결합인덱스(schedule_t_pk)

구성 컬럼 중stadium_id컬럼에 대한 조회조건이 정의되지 않았기때문이다.

  

 

개선후>>

select/*+ ordered */z.stadium_name, x.sche_date,

              x.hometeam_id, y.player_name, y.position

fromplayer_t y, schedule_t x, stadium_t z

where y.team_id = x.hometeam_id

and x.gubun = 'S'

and x.sche_date = '20020911'

and x.stadium_id = z.stadium_id

and y.position = 'GK'

 

SELECT STATEMENT Hint=CHOOSE

 NESTED LOOPS

(player_t, schedule_t결과의1행당 유니크이므로1번랜덤액세스=>19)

   NESTED LOOPS

(schedule_t_pkunique이고where조건에 다 있으므로19

랜덤액세스: 42+ 19=> 61)

     TABLE ACCESS BY INDEX ROWID    PLAYER_T(42행 검색)

       INDEX RANGE SCAN     PLAYER_T_X5

     TABLE ACCESS BY INDEX ROWID    SCHEDULE_T

       INDEX RANGE SCAN     SCHEDULE_T_PK

   TABLE ACCESS BY INDEX ROWID      STADIUM_T

     INDEX UNIQUE SCAN      STADIUM_T_PK

 

 

 

2.조인순서 변경 않고 랜덤액세스 감소(1:M에서M쪽의 건수줄이기)

-조인하기 전에GROUP BY를 사용하여 그룹화한 다음 조인을 하면

두 테이블간으 조인횟수를 줄일 수 있다.

        1)

        SELECT y.team_name, cnt

        FROM (

              SELECT team_id, count(*) cnt

              FROM player_t

              WHERE nation IS NULL

              GROUP BY team_id) x, team_t y

        WHERE x.team_id = y.team_id

        ORDER BY y.team_name

 

SELECT STATEMENT Hint=CHOOSE

 SORT ORDER BY

   NESTED LOOPS

(결과값10행에 대해team_t_pk에 의해1:1조인하여10번 랜덤액세스)

VIEW(결과값:10)

       SORT GROUP BY

         TABLE ACCESS FULL  PLAYER_T

     TABLE ACCESS BY INDEX ROWID    TEAM_T

       INDEX UNIQUE SCAN    TEAM_T_PK

 

 

3.조인 방식의 차이

 

    

Nested Loop

Sort Merge

Hash

테이블을 순차적으로 스캔.

테이블을 동시에 스캔

 

선 처리된 테이블에 종속.

각자 처리하므로 독립적

 

연결고리 상태에 따라 영향.

연결고리 상태에 영향없음.

 

좁은 범위 처리에 유리.

넓은 범위처리에 유리.

 

실행계획:NESTED LOOP

실행계획:MERGE JOIN

 

 

Nested loop조인의 장단점 설명

 

1.    Nested loop조인은 데이터를 랜덤 액세스에 의해 접근하기 때문에 그 결과

집합이 많다면 수행속도가 저하.

2.    드라이빙테이블은 크기가 작거나, where절 조건을 사용하여 적절히 결과집합

제한.

3.    Driven테이블에는 조인을 위한 적절한 인텍스 생성.

4.    연결고리가 되는 컬럼은unique또는 분포도가 좋은 컬럼에 대한 인덱스사용.

 

 

   드라이빙 테이블-첫번째로 액세스되는 테이블로 조건 절에 의해 선택되어지는 결과

집합의 크기가 가장 중요.

 

Ec_course

Ec_course_sq

Ec_apply

1            N             1         N

 

 

 

1

2

3

 

 

 

 

 


 

    * 1을 드라이빙으로 선택시.

    ‘1’에서‘2’로 조인시에는2002년도에712과정에 신청한 사람이2000명이므로

2000번의 조인작업이 수행되어 조인결과집합이 생성.

‘2’에서‘3’으로 조인시 다시2000번의 조인작업이 수행되어2000건의 조인결과

결국 총4000건의 조인작업수행.

     * 3을 드라이빙으로 선택시.

‘3’에서‘2’로 조인시에는712과정정보1건에 조인작업이1번수행되어10row의 결과집합구성해서 해당결과집합을 드라이빙으로 해서‘1’번테이블과 조인을 수행

하면10번의 조인으로 결과집합도2000행이 생김.

 

4.범위 검색(BETWEEN)POINT검색(IN)

1)

 SELECT deptno, job, empno

 FROM emp

 WHERE job=’MANAGER’

 AND deptno BETWEEN ‘10’ AND ‘20’

 

 설명:인덱스 첫번째컬럼인DEPTNO가 범위조건이므로JOB의 조건을 만족하는

자료유무와 관계없이DEPTNO의 범위만큼 계속 인덱스 스캔.

 

SELECT deptno, job, empno

 FROM emp

 WHERE job=’MANAGER’

 AND deptno IN (’10’,’20)

 

 설명: 10, 20DEPTNO만큼의‘=’조건으로 분리해서 합친다.

 

 2)

        SELECT sche_date, stadium_id, home_score, awayteam_id,

away_score

        FROM schedule_t

        WHERE gubun='S'

      ANDsche_date BETWEEN '20020801' AND '20030831'

 

      실행계획:

SELECT STATEMENT Hint=CHOOSE                            

 TABLE ACCESS BY INDEX ROWID      SCHEDULE_T                  

   INDEX RANGE SCANSCHEDULE_T_PK                                                 

      설명: stadium_idwhere조건에서 빠져있으므로sche_date BETWEEN

 '20020801' AND '20030831'까지 데이터를 추출하기 위해gubun=’S’

의 모든 데이터를 검색해야 한다.

 

 3)à특정경기장에 대한 조건추가.

 개선전>>

        SELECT sche_date, stadium_id, home_score, awayteam_id,

away_score

        FROM schedule_t

        WHERE gubun='S'

        AND stadium_id IN (SELECT stadium_id FROM stadium_t)

      AND sche_date BETWEEN '20020801' AND '20030831'

 

SELECT STATEMENT Hint=CHOOSE

 NESTED LOOPS

   TABLE ACCESS BY INDEX ROWID      SCHEDULE_T

     INDEX RANGE SCANSCHEDULE_T_PK

   INDEX UNIQUE SCAN STADIUM_T_PK

 

설명)schedule_t을 먼저 인덱스 스캔하여STADIUM_T_PK에 조인

     불필요한 조인 발생해서 수행속도가 악화되었다.

     stadium_tstadium_t_pk를 가지고 있으므로 나중에 읽겠다고 생각.

 

주의)서브쿼리를 사용하여IN조건 추가시는 서브쿼리가 반드시Driving테이블

이 되어야 한다.

개선후>>

        SELECT sche_date, stadium_id, home_score, awayteam_id,

away_score

        FROM schedule_t

        WHERE gubun='S'

        AND stadium_id IN (SELECT stadium_id||’’ FROM stadium_t)

      AND sche_date BETWEEN '20020801' AND '20030831'

 

     실행계획)

SELECT STATEMENT Hint=CHOOSE

 NESTED LOOPS

   VIEW      VW_NSO_1

     SORT UNIQUE

       TABLE ACCESS FULL    STADIUM_T

   TABLE ACCESS BY INDEX ROWID      SCHEDULE_T

     INDEX RANGE SCANSCHEDULE_T_PK

 

설명)STADIUM_TFULL스캔한 후schedule_t_pkNested Loop조인을

     통해서 실행계획을 분리한다.

 

4)

 개선전>>

 SELECT sale_date, product, qty * amount

 FROM sales_per_date

 WHERE sale_date between ‘20020911’ and ‘20020920’

 AND product = ‘TTL’

 

 설명:sale_date + product컬럼으로 구성되어 있을 때

      sale_date조건이BETWEEN을 사용한 범위 조건으로 지정되어 있어

      PRODUCT컬럼이EQUAL조건이어도 처리범위가 줄지 않았다.

 

       

       개선후>>

SELECT sale_date, product, qty * amount

 FROM sales_per_date

 WHERE sale_date IN (select date_ymd FROM copy_ymd

where date_ymd between ‘20020911’

and ‘20020920’)

 AND product = ‘TTL’

 

 index:date_ymd

        sale_date + product

 

 sale_date조건의in에 의해 분리되어 합쳐짐.

 

인덱스 매칭률(rbo에서 인덱스의 선택기준)

:계산식 = equal조건으로 사용된인덱스컬럼수/인덱스구성컬럼수

 

 

-고려해야 할 경우

.두개이상의 인덱스가 있을 경우

.신규인덱스 생성시

.기존인덱스에 하나이상의 컬럼추가시

 

기준1: equal조건에서 인덱스매칭률이 높은 것 선택.

sales

ix1_sales =부서+기준일자

ix2_sales =품목

 

select *

from sales

where부서= ‘843’ and기준일자= ‘970518’ and품목=’B023’

 

인덱스변경전에서ix1_sales를 사용한다.

 

Ix1_sales에 순번을 추가 한경우 인덱스매칭률이

Ix1_sale :부서,기준일자/부서,기준일자,순번= 2/3 = 66%

Ix2_sale :품목/품목= 1/1 = 100%

가 되어서ix2_sale을 사용하게 된다.

 

기준2:인덱스에서 정의된 컬럼순서로연속된 경우만 인정.

기준3:매칭률이 같을 경우에는 인덱스에 사용된컬럼수가 많은 것을 선택.

기준4:매칭율이 같고 인덱스에 사용된 컬럼수가 같으면최근에 생성된 것선택

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

사용자지정 저장형 함수의 특징.

1.SQL내에서 절차형 처리

2.독립적인 오브젝트(다른 것에 의존하지 않음)

3.단일값을 리턴(저장형 함수가 리턴하는 값은 하나만 가능하다.)

 

-저장형함수를 여러 번에 걸쳐 사용시.

SELECT item,

       ITEM_AMT_FUNC(item, sysdate)당일매출,

       ITEM_AMT_FUNC(item, sysdate-1)전일매출,

       (ITEM_AMT_FUNC(item,sysdate)–

ITEM_AMT_FUNC(item,sysdate-1))*100 / ITEM_AMT_FUNC(item, sysdate)증감률

FROM재고자산

WHERE분류코드=‘110’

 

 

이 때 저장형함수는 반복수행.

 

 

SELECT item,당일매출,전일매출, (당일매출-전일매출)*100/당일매출AS증감률

FROM (

       SELECT item,

              ITEM_AMT_FUNC(item, sysdate)당일매출,

              ITEM_AMT_FUNC(item, sysdate-1)전일매출

       FROM재고자산

       WHERE분류코드=‘110’

       

)

 

 

.앞의 경우와 일량(저장형함수가 위의 경우와 동일한횟수를 반복)이 같은 이유는 인라인뷰

집합은 실제 물리적으로 존재하지 않기 때문이다.

 

 

 

 

 

 

 

 

 

 

 

SELECT item,당일매출,전일매출, (당일매출-전일매출)*100/당일매출AS증감률

FROM (

       SELECT item,

              ITEM_AMT_FUNC(item, sysdate)당일매출,

              ITEM_AMT_FUNC(item, sysdate-1)전일매출

       FROM재고자산

       WHERE분류코드=‘110’

       GROUP BY ITEM

       )

 

.위 두가지의 경우와 다르다. GROUP BY를 하면 인라인뷰의 처리결과가 바로 추출되지

못하고 내부적으로 저장된 후2차가공을 거쳐야 운반단위로 옮겨진다.그러므로 인라인뷰

내에 있던 함수의 수행결과는 이제 더 이상 함수가 아니라 내부적으로 저장된 집합의

상수값이 된다,그러나GROUP BY때문에전체범위처리방식으로 바뀌어 부담이 될

수도 있다.

 

<<대안1>>

 

1.리턴결합하여돌려주는데나중분할할 수 있도록고정길이로 해야 한다.

(TO_CHAR, RPAD사용해서)

2.리턴된 함수값을 다시 분할하기 위해 함수의 리턴값을 여러 번에 걸쳐 기술해야 하며

함수를 수행시킨SELECT문이GROUP BY되어 있지 않다면저장형함수는반복수행되므로

조심해야 한다.

 

 

 

 

 

 

4.로우단위별 실행.

 

SELECT사번,

          FUNC_6(사번, col3) 

FROM ( SELECT x.사번,

                FUNC_1(x.부서)         col1,

                Max(FUNC_2(y.col2))col2,

                   sum(y.본봉)         col3

   FROM 사원x,급여y

             WHERE x.사번= y.사번

             AND x.부서= ‘1100’

             AND y.년월between ‘199801’ and ‘199806’ 

             ANDFUNC_3(x.사번)> 1000

             ANDFUNC_4(y.항목)= ‘ABC’

             AND y.COL4 =FUNC_5(sysdate)

             AND y.COL5 > 100

  GROUP BY x.사번,FUNC_1(x.부서)) ;

 

FUNC_1(x.부서)SELECT에도 있고GROUP BY에 있다,

  에 있는 함수만 수행되고에 있는 함수는 수행하지 않는다.

  에 있는 함수는 두개의 테이블을 조인하고WHERE의 나머지 조건들을

  모두 체크하여성공한 결과의 집합(GROUPBY할 대상로우들)에 대해서 한번씩

  수행된다.SELECT-LIST에 있는 함수가 수행되지 않는 이유는SELECT-LIST

  가장 마지막처리하여추출하므로 이미GROUP BY에 의해 내부적으로 저장된

  로우에서 처리되므로에 있는 함수는 단지GROUP BY된 컬럼을 의미한다.

 

◆ ⑥의FUNC_3의 입력값은X.사번

  1.사원테이블을 먼저 액세스하여급여테이블을 조인하는NESTED LOOP

    일때는사원테이블을 액세스한 로우 수만큼 수행

  2.부서에 인덱스가있다면 먼저 액세스한다면인덱스를 성공적으로 통과

하여 테이블을 액세스한로우에 대해서만FUNC_3이 수행

  3.전체테이블을 스캔한다면 사원테이블의모든로우에 대해함수수행

하므로 전체테이블스캔을 하더라고부서코드를 먼저 체크하여성공한

로우들에 대해서하도록 하는 것이 좋으나 그렇게 수행되지 않음.

  4. X.사번과Y.사번선택시에 사원:급여가1:M이므로FUNC_3(Y.사번)으로 하면

     함수수행횟수증가하므로 훨씬 손해이다.

의 함수FUNC_4‘Y.항목을 입력값으로 하였으므로 당연히급여테이블을

  액세스한 로우수만큼수행한다.

  1.조인되는 급여테이블의 연결고리가사번+급여년월로 되어 있다면 이 인덱스를

     경유한 로우들만 수행

  2.사번이라면 모든 급여년월의 로우들에도 함수수행.

  3. ‘사원테이블을 먼저 액세스하고급여테이블이 연결되는NESTED LOOP형 조인

이라면 수행횟수는 달라진다.

  4. SORT MERGE형 조인으로 수행되었다면 각각의 집합이 액세스한 로우수 만큼 수행.

 

◆ ⑧에 있는 함수FUNC_5상수값을 입력

  급여테이블이 먼저 액세스될 때

  1.⑧에 있는Y.COL4의 조건이 단지 체크조건으로만 사용된다면테이블액세스

     로우만큼 함수가 수행된다.

  2.먼저 수행된다면 상수값입력시에 같이 단 한번만 수행된다.

즉 이 컬럼이드라이빙인덱스로 사용된다면 함수는 먼저한번만 수행되어Y.COL4에게

 상수값을 제공한다.

 

급여테이블이 나중에 연결될 때.

1.연결고리 인덱스가사번+급여년월로 되어 있고⑤ 라인의 조건을AND급여년월

  = FUNC_5(SYSDATE)로 했다고 가정하면 먼저 수행되는사원테이블의성공한 로우

      들이급여테이블을연결하러 오는순간마다한 번씩수행한다.

   (조언:상수값으로 처리되는함수SQL내로 끌어들이는 것은옳은방법이아니,

SQL이 수행되기전에 먼저 별도로 수행시켜 그 결과값을 상수값으로 저장해 두고

SQL에서는 이 상수값과 비교하는 것이 좋다.)

 

◆ 조건의 체크기능으로 사용된 함수는 조건이 기술된 위치에 따라서 수행횟수가 달라진다.

  ⑨의 조건을⑦이나 ⑧앞으로 옮기면 함수의 수행 횟수가 달라진다.

  만약 ⑦⑧⑨의 조건이급여테이블이 액세스된 후에 체크조건으로 사용되었다면 가장

  먼저 ⑨의 조건이 체크되고 성공한 경우만 ⑧의 조건을 체크한다.물론 ⑦의 조건도

  마찬가지로 ⑧의 조건에 성공한 로우들만 체크한다.

  논리적인 측면이나 드라이빙결정에 대해서는WHERE절에 기술한 조건의 순서는 전혀

  의미가 없지만 같은 체크조건들 사이에는 그들만의 순서가 존재한다.

  그러므로 함수는 가능한 앞에 기술하는 것이 유리하며 상수값과 비교되는 조건들을

  나중에 기술하는 것이 유리한다 이들간에도 실패할 확률(범위를 빨리 좁혀줄 수 있는)

 높은 조건들을 조금이라도 나중에 기술하는 것이 바람직하다.

 

③의 함수GROUP BY가 있는SELECT-LIST에 사용되었으므로GROUP BY한 결과의 로우

  마다 수행할 것처럼 보이지만 이 함수는GROUP BY절에 기술한의 함수와 동일한 횟수

  가 수행된다,WHERE을 모두만족한 모든 로우들에 대해함수가 수행된다.

  그러므로 만약GROUP BY한 결과에 대해서만 함수를 수행시키고자 한다면 지금까지의

  집합을 인라인뷰로 묶고 ①의 함수와 같이 마지막SELECT-LIST에 기술.

출처 :Tong - roverto님의 MS-SQL통