메뉴 건너뛰기

bysql.net


6. Sort Area를 적게 사용하도록 SQL 작성

  • 소트 연산이 불가피 할 시, 메모리 내 처리 완료하도록 함
  • Sort area 크기를 늘리기보다 적게 사용하는 방법을 먼저 찾을 것


(1) 소트를 완료하고 나서 데이터 가공하기

  • Sort Area를 적게 사용하는 쿼리는?

              " 1번 "

SELECT LPAD(상품번호, 30) || LPAD(상품명, 30) || LPAD(고객id, 10)

    || LPAD(고객명, 20) || TO_CHAR(주문일시, 'yyyymmdd hh24:mi:ss')

FROM   주문상품

WHERE  주문일시 BETWEEN :start AND :end

ORDER  BY 상품번호;


              " 2번 "

SELECT LPAD(상품번호, 30) || LPAD(상품명, 30) || LPAD(고객ID, 10)

    || LPAD(고객명, 20) || TO_CHAR(주문일시, 'YYYYMMDD HH24:MI:SS')

FROM   (

  SELECT 상품번호, 상품명, 고객ID, 고객명, 주문일시

  FROM   주문상품

  WHERE  주문일시 BETWEEN :START AND :END

  ORDER  BY 상품번호

);


    • 1번 쿼리 : 가공된 결과치를 Sort Area를 담음 - 레코드당 105 (=30+30+10+20+15) 바이트
    • 2번 쿼리 : 가공되지 않은 상태로 정렬 완료하고 최종 출력시 가공하므로 Sort Area 적게 사용


(2) TOP-N 쿼리

  • 소트 연산(=값 비교) 횟수를 최소화하고, Sort Area 사용량 감소 가능
  • Top-N 쿼리 작성법
    • SQL Server or Sybase

SELECT TOP 10 거래일시, 채결건수, 체수량, 거래대금

FROM   시간대별종목거래

WHERE  종목코드 = 'KR123456'

AND    거래일시 >= '20080304';


    • IBM DB2

SELECT 거래일시, 채결건수, 체수량, 거래대금

FROM   시간대별종목거래

WHERE  종목코드 = 'KR123456'

AND    거래일시 >= '20080304'

ORDER BY 거래일시

FETCH FIRST 10 ROWS ONLY;


    • ORACLE : Inline View로 한번 감싸야 함

SELECT * FROM   (

   SELECT 거래일시, 채결건수, 체수량, 거래대금

   WHERE  종목코드 = 'KR123456'

   AND    거래일시 >= '20080304'

   ORDER BY 거래일시

WHERE  ROWNUM <= 10;


Execution Plan

------------------------------------------------------------------------------

0    SELECT STATEMENT Optimizer=ALL_ROWS

1  0   COUNT (STOPKEY)

2  1     VIEW

3  2       TABLE ACCESS (BY INDEX ROWID) OF '시간별종목거래' (TABLE)

4  3         INDEX (RANGE SCAN) OF '시간별종목거래_PK' (INDEX (UNIQUE))


  ☞ "종목코드 + 거래일시" 순으로 구성된 인덱스가 존재 시, 옵티마이저는 인덱스 활용으로 order by 연산 대체 가능

※ ROWNUM 조건을 사용해 N건에서 멈추도록 했으므로 조건절에 부합하는 레코드가 아무리 많아도 매우 빠른 수행 속도 낼 수 있음 

☞ 실행계획 상 "count stopkey"



TOP-N쿼리의 소트 부하 경감 원리


  • "종목코드 + 거래일시" 순으로 구성된 인덱스가 없을 경우 

☞ Top-N 쿼리 알고리즘이 효과를 발휘하여 Sort order by 부하 경감


  • Top-N 쿼리 알고리즘 ( rownum <= 10 경우 )

1. 우선 10개 레코드를 담을 배열 할당

2. 처음 읽은 10개 레코드를 정렬된 상태로 담기

3. 읽는 레코드과 맨 우측에 있는 값(=가장 큰 값)과 비교 (반복)

    → 작은 값이 나타날 때 배열 내에서 재정렬 시도하고, 맨 우측 값은 버림


    ☞ 전체 레코드를 정렬하지 않고 오름차순(ASC)으로 최소값을 갖는 10개 레코드를 정확히 찾아냄


        p610.png



효과 측정 : TOP-N 쿼리가 작동할 때


Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production


SQL> create table t as select * from all_objects;


SQL> alter session set workarea_size_policy = manual;


SQL> alter session set sort_area_size = 524288; /* Top-N 쿼리 작동 차이를 알기위해 크기를 작게 설정 */


SQL> set autotrace traceonly statistics


SQL> select count(*) from t;


Statistics

----------------------------------------------------------

         28  recursive calls

          0  db block gets

       1090  consistent gets

       1018  physical reads

          0  redo size

        :


SQL> select *

  2  from (

  3    select * from t

  4    order by object_name

  5  )

  6  where rownum <= 10 ;


Statistics

----------------------------------------------------------

        310  recursive calls

          0  db block gets

       1183  consistent gets

          0  physical reads

          0  redo size

:

          1  sorts (memory)

          0  sorts (disk)

         10  rows processed



효과 측정 : TOP-N 쿼리가 작동하지 않을 때


SQL> select *

  2  from (

  3    select a.*, rownum no

  4    from (

  5      select * from t order by object_name

  6    ) a

  7  )

  8  where no <= 10 ;


Statistics

----------------------------------------------------------

         16  recursive calls

         22  db block gets

       1153  consistent gets

       1238  physical reads

          0  redo size

:

          0  sorts (memory)

          1  sorts (disk)

         10  rows processed




(3) 분석함수에서 TOP-N 쿼리

  • window sort 시에도 rank(), row_number()를 사용하면 TOP-N쿼리 알고리즘 작동 
     ☞ max() 등 함수 사용할 때보다 소트 부하 경감


  • max() 함수 사용

SQL> select id, seq, owner, object_name, object_type, created, status

  2  from  (select id, seq

  3              , max(seq) over (partition by id) last_seq

  4              , owner, object_name, object_type, created, status

  5         from t)

  6  where  seq = last_seq;


10 개의 행이 선택되었습니다.


Execution Plan

------------------------------------------------------------------------------------

| Id  | Operation           | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |

------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT    |      |   752K|    70M|       | 21796   (1)| 00:04:22 |

|*  1 |  VIEW               |      |   752K|    70M|       | 21796   (1)| 00:04:22 |

|   2 |   WINDOW SORT       |      |   752K|    61M|    75M| 21796   (1)| 00:04:22 |

|   3 |    TABLE ACCESS FULL| T    |   752K|    61M|       |  1777   (1)| 00:00:22 |

------------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("SEQ"="LAST_SEQ")


Statistics

----------------------------------------------------------

         51  recursive calls

          2  db block gets

       6518  consistent gets

      13603  physical reads

          0  redo size

:

          0  sorts (memory)

          1  sorts (disk)

         10  rows processed


  • rank() 함수 사용

SQL> select id, seq, owner, object_name, object_type, created, status

  2  from  (select id, seq

  3              , rank() over (partition by id order by seq desc) rnum

  4              , owner, object_name, object_type, created, status

  5         from   t)

  6  where rnum = 1;


10 개의 행이 선택되었습니다.


Execution Plan

-----------------------------------------------------------------------------------------

| Id  | Operation                | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |

-----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT         |      |   752K|    70M|       | 21796   (1)| 00:04:22 |

|*  1 |  VIEW                    |      |   752K|    70M|       | 21796   (1)| 00:04:22 |

|*  2 |   WINDOW SORT PUSHED RANK|      |   752K|    61M|    75M| 21796   (1)| 00:04:22 |

|   3 |    TABLE ACCESS FULL     | T    |   752K|    61M|       |  1777   (1)| 00:00:22 |

-----------------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("RNUM"=1)

   2 - filter(RANK() OVER ( PARTITION BY "ID" ORDER BY INTERNAL_FUNCTION("SEQ") DESC )<=1)


Statistics

----------------------------------------------------------

          1  recursive calls

         66  db block gets

       6518  consistent gets

         63  physical reads

          0  redo size

:

          0  sorts (memory)

          1  sorts (disk)

         10  rows processed





  • 오라클 고도화 원리와 해법 2 (bysql.net 2011년 1차 스터디)
  • 작성자: 위충환 (실천하자)
  • 최초작성일: 2011년 06월 13 일
  • 본문서는 bysql.net 스터디 결과입니다 .본 문서를 인용하실때는 출처를 밝혀주세요. http://www.bysql.net
  • 문서의 잘못된 점이나 질문사항은 본 문서에 댓글로 남겨주세요. ^^

번호 제목 글쓴이 날짜 조회 수
40 10. 실체화 뷰 쿼리로 재작성 suspace 2011.06.07 5531
39 9. Outer 조인을 Inner 조인으로 변환 darkbeom 2011.06.07 7834
38 8. 공통 표현식 제거 darkbeom 2011.06.07 5223
37 12. 기타 쿼리 변환 [3] 실천하자 2011.06.03 6646
36 4. 조건절 Pushing 실천하자 2011.05.31 7021
35 7. OR-Expansion 멋진넘 2011.05.31 8720
34 6. 조인 제거 멋진넘 2011.05.30 4595
33 5. 조건절 이행 휘휘 2011.05.30 5407
32 2. 서브쿼리 Unnesting darkbeom 2011.05.16 19700
31 3. 뷰 Merging 실천하자 2011.05.15 23387
30 7. 비용 휘휘 2011.05.03 6173
29 1. 쿼리 변환이란? 실천하자 2011.05.02 4927
28 8. 통계정보 Ⅱ [1] 멋진넘 2011.04.30 31087
27 5. 카디널리티 suspace 2011.04.26 5953
26 4. 통계정보 Ⅰ darkbeom 2011.04.26 18094
25 6. 히스토그램 실천하자 2011.04.25 10920
24 3. 옵티마이저의 한계 멋진넘 2011.04.19 7857
23 1. 옵티마이저 file 실천하자 2011.04.18 11211
22 2. 옵티마이저 행동에 영향을 미치는 요소 휘휘 2011.04.18 5094
21 8. 고급 조인 테크닉-2 file suspace 2011.04.05 7018