안녕하세요.
쿼리 튜닝하다가 이해 못할 현상을 발견하여 전문가님들의 의견을 구합니다.
50초가 걸리는 쿼리의 서브쿼리 SELECT 절에 top 1000000 넣었더니,
결과 데이터는 동일하였고 소요시간이 50초에서 2초로 줄었습니다.
대략 쿼리는 이렇게 생겼습니다. (빨간색이 추가한 부분입니다.)
SELECT * FROM ( SELECT top 1000000 * FROM A WHERE A.x = 'XXX' UNION ALL SELECT top 1000000 * FROM B WHERE B.y = 'YYY' ) p1 LEFT OUTER JOIN ( SELECT id,SUM(amount) amount FROM ( SELECT top 1000000 * FROM A WHERE A.x = 'XXX' UNION ALL SELECT top 1000000 * FROM B WHERE B.y = 'YYY' ) GROUP BY id ) p2 ON p1.id = p2.id , C WHERE p1.id = C.ref_id AND NOT EXISTS ( SELECT 1 FROM E WHERE p1.id = E.ref_id AND p2.amount = E.amount ) |
제가 이상하게 생각하는 점은,
top 1000000 없이 아래 처럼 실행한 경우.
1) SELECT * FROM A WHERE A.x = 'XXX';
2) SELECT * FROM B WHERE B.y = 'YYY';
결과 데이터가 1) 은 대략 1000개, 2)는 대략 100 개 밖에 안되었고,
결국 top 1000000 은 결과 데이터에는 아무런 영향도 미치지 않았다는 것입니다.
(사실 A, B 테이블 모두 레코드가 1000000 개가 되지 않습니다.)
혹시 캐시가 남았나 싶어서 조건도 약간씩 바꿔보고 top 1000000 구문도 넣었다 뺐다 해봤는데 결과는 마찬가지였습니다.
어떻게 이럴 수 있죠?
예상실행계획을 봐도 top 절이 추가된 것을 제외하고는 동일한 구조를 하고 있었습니다.
저는 ms sql 2008 을 사용하고 있습니다.
의견 부탁드려요 ㅠ
Comment 7
-
향지
2014.08.01 16:34
-
ㅎㅌㅎㅌ
2014.08.04 11:18
돌려보니
[1]
p1 부분은 거의 특이한 차이점이 없어보입니다.
[2]
그런데 p2 부분은
전체적으로 Executes 값이 많이 줄었고, top 하위에 sort 하는 부분도 생겼네요.
또 Index Spool 이 Table Spool 로 바뀌었습니다.
[3]
그리고 아래 첨부 이미지 6번째에 보면
Left Outer Join 다음에 OUTER REFERENCES 라는 부분이 WHERE 로 바뀌었습니다.
이것때문에 p2 부분의 Rows 값이 영향을 받지는 않았을까요?
-
minsouk
2014.08.01 18:35
.
-
ㅎㅌㅎㅌ
2014.08.04 11:21
제 사이트가 아니고 회사 프로젝트에 들어있는 쿼리라 XML 로 올려드리긴 좀 그럴것 같네요~ 죄송합니다~ 위 댓글에 첨부한 이미지 파일을 참조해주세요^^
-
minsouk
2014.08.04 13:37
.
-
ㅎㅌㅎㅌ
2014.08.04 20:00
말씀해주신 부분을 가지고 확인해보았습니다.
(p1을 첫번째 유니온의 결과, p2를 두번째 유니온한 결과를 group by 처리한 것이라고 한다면,,)
p1 부분에서 Concatenation (위 캡쳐 7번째 라인) 의 결과로 [Union1016] 이 생깁니다.
첫번째 쿼리에서 304896개를 clustered Index seek 할 때는 LEFT OUTER JOIN 의 ON 절에 해당하는 조인 조건을 미리 처리하기 위해 [Union1016]가 포함된 조건문이 WHERE 절에 추가 되어 있었습니다. 즉 p1 과 어차피 LEFT OUTER JOIN 할꺼니깐, p2를 셀렉트 하는 과정에서 group by 할 데이터 양도 줄일겸(?) 한 번에 해버리려고 한 것 같습니다. 물론 결과는 오히려 성능저하로 나타났지만 말입니다.
그러나 두번째 쿼리에서는 p2안의 서브쿼리에서 [Union1016] 을 사용하려는 부분이 빠져있었습니다. p2안에서 [Union1016] 조건 으로 미리 데이터를 잘라내면 순서가 엉켜버리고 그러면 TOP 절이 다른 결과를 만드어낼 우려가 있어서 여기서는 적용하지 않은것 같다는 것이 제 생각입니다.
제가 가능한 이야기를 하고 있는건지 모르겠네요^^a
기회가 되면 좀더 분석 및 공부를 해봐야할것 같네요.. 도움 주셔서 감사합니다.
(아쉽지만 윗분들이 어떻게 생각하실지 몰라서 실행계획은 아직 공유해드리지 못했습니다..;)
-
ㅎㅌㅎㅌ
2014.08.06 09:22
네 감사합니다! 이해하기 쉬운 예제이네요~ 말씀하여주신 책도 한 번 찾아보도록 하겠습니다.
예상 실행계획 말고 실제 실행계획도 보고싶네요..
의심되는 부분은
옵티마이저가 실행계획 만들때
top 부분의 우선순위가 높습니다? 높다라고 해야되나.....
top이 없을때는 다른거부터 처리하다가...
top을 넣었기 때문에 top 부분부터 연산하고 다음을 연산하려고 할수도 있습니다.
set statistics io on
set statistics profile on
해보시고 실행시켜서 체크해보시면 어떨까 합니다.