두가지 소스의 성능차이 질문입니다. 0 3 1,629

by 김태성 [2015.06.17 13:35:49]


먼저 두가지 테이블이 있습니다.(필드명에 선그어진건 키를 의미합니다)

TABLE : ITEMS

item_no, item

10         FD

20         CD

30         MO

40         DVD

TABLE : SALESHISTORY

sale_date, item_no, quantity

07-10-01  10         4

07-10-01  20        10

07-10-01  30         3

07-10-03  10        32

07-10-03  30        12

07-10-04  20        22

07-10-04  30        7

이 두 테이블에 대해서 아이템 번호별로 판매량(quantity)의 합계를 내는건데 결과는 아래와 같이 됩니다.

item_no,  total_qty

10          36

20          32

30          22

40

이 문제에 대해서 두가지의 방법이 제시되어있는데 하나가

SELECT
   IT.ITEM_NO
  ,SH.TOTAL_QTY
FROM ITEMS2 IT LEFT OUTER JOIN
(
  SELECT
     ITEM_NO
    ,SUM(QUANTITY) AS TOTAL_QTY
  FROM SALESHISTORY
  GROUP BY ITEM_NO
) SH
ON IT.ITEM_NO = SH.ITEM_NO;

이거입니다. 책에서 이 소스에 대해 퍼포먼스적 단점으로 지적하는 부분이

중간뷰(SH)를 만드는점이 퍼포먼스를 저하시키는 원인1.

또 하나가 모처럼 item_no가 일의(一意)가 되어도 SH자신은 주키의 인덱스가 없기때문에 결합조건으로 이용할 수 없습니다. 원인2 라고 말하고 있습니다. 

원인1은 이해가 됩니다.

원인2가 잘 이해가 안되는데..요즘 인덱스를 공부중이라 제대로 이해하고 넘어가고 싶습니다.

원인2에 대해 질문드리기 앞서서 같은 처리를 하는 다른 소스를 하나 더 적겠습니다.

SELECT
   IT.ITEM_NO
  ,SUM(QUANTITY) AS TOTAL_QTY
FROM ITEMS2 IT
LEFT OUTER JOIN SALESHISTORY SH
ON IT.ITEM_NO = SH.ITEM_NO
GROUP BY IT.ITEM_NO
;

걍 결합 한 다음에 그룹바이 한 소스입니다. 실제로 데이터를 100만건 넣고 확인해 봤을때 평균 위에거가 1.5초 아래거가 0.6초정도로 차이가 상당히 납니다.

이제 질문으로 넘어가고 싶은데...

첫번째 질문은. 아래의 소스에서는 인덱스가 이용되고 있는가? 입니다.

인덱스를 붙이고 안붙이고의 차이를 보기위해서 일부러 테이블에 키를 삭제하고 인덱스도 삭제하고 테스트를 해봤는데 인덱스를 삭제하고 테스트해도 빨라진 것 같지않아서 의문을 갖게 되었습니다.

두번째 질문.

아래의 소스는 인덱스가 동작하고 있다고 하면, 위의 소스가 인덱스가 안움직인다고 책에서 말하는 이유는. SH라는 뷰에 대해서 인덱스가 설정되어저 있지 않기때문에 ON조건에서 SH.ITEM_NO를 해도 SH는 인덱스가 없으므로 빨라지지 않는다 이런 얘기인가요?

마지막 질문.

인덱스에 대해서 조사할때 키가 여러개일때 인덱스가 작동하는 조건으로는 조건이 주 키 하나만 있거나. 복수 조건일 경우 주 키가 가장 먼저 조건에 쓰여젔을때 인덱스가 움직인다고 알고 있습니다.(제가 잘 못알고있을지도 모름)

그러면 SALESHISTORY에서 sale_date필드가 주 키고, item_no가 두번째 복수 키일경우 item_no만으로 결합했을때에는 인덱스가 작동하지 않는다고 생각하는데 이게 맞는지 알고 싶습니다. 이게 맞다면 첫번쨰 질문도 인덱스는 움직이고 있지 않다 가 정답이 되겠네요.

질문 내용이 이해가 안되거나 하시면 보충설명 드릴테니 리플 부탁드립니다 _ _

by 아발란체 [2015.06.17 15:31:20]

1. 인덱스가 이용이 되는가?

실행 계획을 보시면 이용 여부를 확인 할 수 있습니다. 책과 다르게 인덱스가 사용되지 않을 수 있습니다. 중간뷰를 만드는 것이 무조건 나쁜 것은 아니고 오히려 인라인뷰는 선별 작업을 하기 위해 많이 쓰이는 것 같습니다. 그러나 지금 보면 쓰지도 않은 이력 테이블 모든 데이타를 item_no별 집계를 하고 여기서 items테이블에 의해 필요한 item_no를 선별하고 있는데, 튜닝을 한다면 사용하는 item_no 값을 가진 데이타를 먼저 선별하고 item_no별 집계를 하는 것이 빠릅니다. 또한 등치(=) 조인이기 때문에 루프 브레이크가 걸리는 exists 함수가 효과적일 것 같습니다.

 

2. sh가 테이블 이름을 보면 이력 테이블로 인덱스가 없는 것 같은데 데이타 양이 많다면 조인 조회시 무진장 느립니다. 이력 테이블로 인덱스가 없다면 일반적으로 서비스 하는 테이블이 아니기 때문에 느린 것이 당연할 것 같습니다. 역시 실행 계획을 보면 무인덱스에 조인 조건절이 있어 풀스캔으로 이중 루프를 돌기 때문에 데이타가 많다면 무진장 느린 것이 당연합니다.

 

3. 선행 컬럼이 조건식이 빠져도 무조건 인덱스를 타지 않거나 이용 못하는 것은 아니고 상황에 따라 옵티마이저가 인덱스 스킵 스캔(index skip scan)을 하거나 힌트를 지정하여 인덱스를 사용 할 수 있습니다.

(관련 강좌 : http://wiki.gurubee.net/pages/viewpage.action?pageId=6816272)


by 겸댕2후니 [2015.06.17 16:05:51]

실행계획을 올려주셔야 확실히 알 수 있습니다.

위와 같은 상황에서 NL JOIN이 일어나는지, Sort merge 또는 Hash Join이 일어나는지

각각의 조인 방식에서 사용하는 Index는 완전히 다를 수 있구요,

또 위에 서브쿼리로 미리 Group by 처리를 한 후, 조인을 하였을 때 실행속도가 느린 것은

Outer Join으로 인해 드라이빙테이블이 적절하지 않아 그런 결과가 나온 것 같습니다.

Outer Join이 아니고, 일반조인의 경우에 단순히 Join을 하는 것보다는

첫번째 쿼리처럼 미리 그룹바이절을 처리 한후, 그 결과를 조인하는 것이 더 좋은 성능을 보입니다.


by 김태성 [2015.06.18 12:32:34]

두분 다 감사합니다. 실행계획이란걸 처음 알았네요. 인덱스가 조금은 생각했던거랑 다르게 움직이는데 그래도 실행계획 보니까 어떻게 돌아가는지 조금 알 것 같습니다.

내용이 어려워서 솔직히 다 이해는 안가는데 ㅋㅋ 좀 더 꼼꼼히 고민좀 해봐야게네요 ㅎㅎ

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입