-- 원본쿼리
SELECT *
, CASE WHEN Gubun = 2 THEN [dbo].[fn_Get상품이미지경로](상품번호, 1) else '' END AS 상품이미지경로
FROM 문의사향뷰
WHERE site='D' and Step=0
ORDER BY regdate DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
-- 10
-- CPU 시간 = 3421ms, 경과 시간 = 3432ms
-- AllQnA라는 QandA 일반 Q&A테이블과 GoodBBS라는 상품문의 테이블을
-- union all 해놓은 뷰를 통해 쿼리 수행
-- 해당 뷰는 여러용도로 활용하기 위해 가져올수 있는 대부분의 컬럼을 명시한 형태
-- 튜닝쿼리
select a.gubun
, a.게시물번호
, isnull(b.UserID, c.UserID) as userid
, isnull(b.title, c.title) as title
, isnull(b.contents, c.contents) as contents
, isnull(b.name, c.name) as name
, isnull(c.email, '') as email
, a.regdate
, isnull(b.hit, c.hit) as hit
, isnull(b.ref, c.ref) as ref
, isnull(b.re_level, c.re_level) as re_level
, 0 as step
, isnull(b.주문번호, '') as 주문번호
, isnull(c.상품번호, 0) as 상품번호
, isnull(b.select1, '商品Q&A') as category
, 'D' as site
, isnull([dbo].[fn_Get상품이미지경로](c.gserial, 1), '') as 상품이미지경로
from (
SELECT gubun, 게시물번호, regdate
FROM (
SELECT 1 AS gubun, 게시물번호, regdate
FROM 일반문의 with(nolock)
WHERE RegDate >= '2015-01-01'
and site='D'
and step = 0
UNION ALL
SELECT 2 AS gubun, B.게시물번호, b.regdate
FROM 상품문의 B with(nolock)
join 전체상품뷰 G on B.gserial=G.gserial
WHERE B.assort = '1'
AND B.active = 'Y'
AND B.Userid <> 'Guest'
AND B.RegDate >= '2015-01-01'
and G.카테고리코드 in (2,232,711,362,323)
and b.site='D'
and b.step = 0
) a
ORDER BY regdate DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
) a
left join 일반문의 b with(nolock) on a.gubun = 1
and a.number = b.number
left join 상품문의 c with(nolock) on a.gubun = 2
and a.number = c.number
-- 10
-- CPU 시간 = 218ms, 경과 시간 = 220ms
-- 결과 : 뷰를 해체하여 먼저 대상의 키값 및 정렬 기준이 되는 값들만으로 페이징 처리를 하고
그 후 페이징처리된 10건에 대해서만 각 테이블을 조인하도록 변경하여
최소한의 억세스를 사용하게 해 총 수행시간을 3500ms -> 220ms 로 줄임
* 튜닝 포인트
1. SELECT gubun, 게시물번호, regdate
- 이 역시 많은 개발자 분들이 간과하시는 부분으로 부분처리시에는 필터링을 위한 최소한의 컬럼정보만 사용하면
적당한 인덱스가 있을 경우 커버드인덱스 형태가 될 수도 있고 최소한 불필요한 풀스캔은 막게되므로 중요한 부분
2. left join QandA, GoodBBS
- 페이징처리가 끝나면 이제 실제 필요한 정보를 추출하기 위해 두 테이블 모두 많게는 10번만 스캔하면 됨.
3. contents, email, ref, re_level 등등
- 튜닝은 원본쿼리의 결과를 그대로 나오게 하는 전제이므로 그대로 두었으나
해당 화면을 확인해본결과 내용, 이메일, 조회수 등등은 화면에서 사용하지도 않는 정보였음.
특히 contents는 큰내용이 들어있을 수 도 있으므로 꼭 필요한 정보들만 두고 나머지는 SELECT 절에서 꼭 제거가 필요
4. SQLServer라서 원래 사용하던 AllQnA 뷰를 해체하지 않고도
상단의 fn_GetListImg 펑션(상품이미지테이블에서 해당 이미지 경로 추출)만
직접 해당 테이블로 스칼라 서브쿼리를 하게 변경해도 속도 자체는 튜닝쿼리와 비슷하게 나온다.
다만 내부적으로 비트맵 연산에 병렬처리까지 더해져서 나오게 되는 속도라서 cpu를 불필요하게 많이 사용하게 된다.