내용 잠시 설명 드리면 화면단에서 현재 뿌려진 마지막 글에 seq를 주면 다음 글부터 정해진 개수만큼 조회하는 쿼리 입니다
ord1, ord2, ord3 컬럼은 오더바이 대상 컬럼입니다. 3개중 택 1 입니다.
원본 쿼리
WITH test AS (
SELECT 1 seq, '내용1' content, 1 ord1, 2 ord2, 7 ord3 FROM dual
UNION SELECT 2 , '내용2' , 2 , 5 , 6 FROM dual
UNION SELECT 3 , '내용3' , 7 , 6 , 5 FROM dual
UNION SELECT 4 , '내용4' , 5 , 1 , 4 FROM dual
UNION SELECT 5 , '내용5' , 3 , 3 , 3 FROM dual
UNION SELECT 6 , '내용6' , 6 , 4 , 2 FROM dual
UNION SELECT 7 , '내용7' , 4 , 7 , 1 FROM dual
)
수정중인 쿼리
WITH test AS (
SELECT ROW_NUMBER() over(ORDER BY ord1) NO
, m.*
FROM (
SELECT 1 seq, '내용1' content, 1 ord1, 2 ord2, 7 ord3 FROM dual
UNION SELECT 2 , '내용2' , 2 , 5 , 6 FROM dual
UNION SELECT 3 , '내용3' , 7 , 6 , 5 FROM dual
UNION SELECT 4 , '내용4' , 5 , 1 , 4 FROM dual
UNION SELECT 5 , '내용5' , 3 , 3 , 3 FROM dual
UNION SELECT 6 , '내용6' , 6 , 4 , 2 FROM dual
UNION SELECT 7 , '내용7' , 4 , 7 , 1 FROM dual
) m
)
SELECT * FROM test WHERE no > (SELECT NO FROM test WHERE seq = 5);
이같은 형태로 원래 쿼리를 수정 하고 싶었으나 where 절에 서브 쿼리에 select절에 * 로 하면 원하는 no 값이 나오는데 select절을 no 로 하면 엄한 값이 나옵니다.
해서 플랜 보니깐 이유는 모르겠지만 플랜이 다르게 풀리더라구요;;
원본 쿼리에는 스칼라 서브쿼리랑 조인 형태로 되어있습니다.
질문 내용
1. 한방 쿼리로 처리할수 있는 방법 있을까요??
DB 는 oracle 11g 입니다.
- 원하는 결과
ord | review_seq | user_id | ... | ... | ... | ... | ... | ... | .. | reply_count |
1 | 4 | 2 | ||||||||
2 | 12 | 0 | ||||||||
3 | 11 | 0 | ||||||||
4 | 0 | 0 | ||||||||
5 | 7 | 화면에 보여준 마지막 글 seq | 0 | |||||||
6 | 6 | 0 | ||||||||
7 | 3 | 0 |
표에 review_seq =7 이 화면에 보여진 마지막 글 입니다. ord 6번 이후 데이터를 조회 하고 싶은겁니다.
오더링 기준은 reply_count, favorite_count, create_dt 중에서 1개로 합니다.
- 문제 쿼리
with test AS (
SELECT ROW_NUMBER() over(ORDER BY reply_count desc) ord
, M.*
FROM
(SELECT B.CONTENT_REVIEW_SEQ REVIEW_SEQ ,
A.USER_ID ,
A.NICK_NM ,
A.PROFILE_URL ,
B.CONTENTS ,
F_BETWEEN_DAY(B.CREATE_DT, SYSDATE, 'YYYYMMDD', 'HH24MISS') CREATE_TIME ,
B.CREATE_DT ,
(SELECT COUNT(USER_ID)
FROM ST_CONTENT_RECOMD
WHERE CONTENT_SEQ = 42
AND RECOMD_TYPE = 'R'
AND RECOMD_YN = 'Y'
) FAVORITE_COUNT ,
(SELECT RECOMD_YN
FROM ST_CONTENT_RECOMD
WHERE CONTENT_SEQ = 42
AND USER_ID = '128902655'
AND RECOMD_TYPE = 'R'
) MY_FAVORITE ,
(SELECT COUNT(*)
FROM ST_CONTENT_REVIEW
WHERE TOP_CONTENT_REVIEW_SEQ = B.CONTENT_REVIEW_SEQ
AND USE_YN = 'Y'
) REPLY_COUNT
FROM ST_USER A ,
ST_CONTENT_REVIEW B
WHERE A.USER_ID = B.USER_ID
AND B.CONTENT_SEQ = 42
AND B.USE_YN = 'Y'
) M
)
SELECT * FROM test WHERE ord > (SELECT ord FROM test WHERE review_seq = 7)
;
- where절에 서브쿼리 실행 했을때 플랜 및 결과 값
쿼리 : SELECT ord FROM test WHERE review_seq = 7;
결과 값 : 3
플랜 :
--------------------------------------------------
| Id | Operation | Name |
--------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | TABLE ACCESS FULL | ST_CONTENT_REVIEW |
| 3 | VIEW | |
| 4 | WINDOW SORT | |
| 5 | NESTED LOOPS | |
| 6 | TABLE ACCESS FULL| ST_CONTENT_REVIEW |
| 7 | INDEX UNIQUE SCAN| dIdIST_USER_PK |
--------------------------------------------------
쿼리 : SELECT * FROM test WHERE review_seq = 7;
결과 : 5
플랜 :
----------------------------------------------------------------------
| Id | Operation | Name |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | TABLE ACCESS FULL | ST_CONTENT_REVIEW |
| 3 | SORT AGGREGATE | |
| 4 | FILTER | |
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED| ST_CONTENT_RECOMD |
| 6 | INDEX SKIP SCAN | ST_CONTENT_RECOMD_PK |
| 7 | FILTER | |
| 8 | TABLE ACCESS BY INDEX ROWID BATCHED | ST_CONTENT_RECOMD |
| 9 | INDEX SKIP SCAN | ST_CONTENT_RECOMD_PK |
| 10 | VIEW | |
| 11 | WINDOW SORT | |
| 12 | HASH JOIN | |
| 13 | TABLE ACCESS FULL | ST_CONTENT_REVIEW |
| 14 | TABLE ACCESS FULL | ST_USER |
----------------------------------------------------------------------
1. 페이징 처리의 정렬기준은 유일해야 합니다.
- 정렬기준 항목 reply_count 가 Unique 하지 않네요.
- 정렬기준에 reply_count 외에 review_seq 를 추가하세요.
2. 마지막 seq 를 이용한 next 페이지 구현은
- 페이징 쿼리의 성능 개선을 위한 방법입니다.
- 이 경우 키값등을 이용하여 인덱스 스캔을 유도해야 하는데
- 위 경우엔 키값이 아닌 reply_count 를 이용하여 정렬하네요.
- 이 경우엔 마지막값을 이용한 next 페이지 구현은 의미 없어 보입니다.
- 오히려 성능만 더 떨어질것 같네요.
3. 실제 목록쿼리와는 전혀 상관 없는 서브쿼리가 두개나 붙어 있네요.
- 이걸 왜? 목록쿼리에 붙였는지?
- 별도 쿼리로 빼길 권합니다.
4. 페이징 쿼리 비효율 제거
- 조인 및 함수 사용 후 페이징 하지 마시고
- 조인 및 함수 사용은 페이징 처리 이후로 미루세요.