댓글 조회 패이징 쿼리 질문 드립니다. 0 8 1,273

by 쫀득이 [SQL Query] [2017.04.26 11:04:34]


내용 잠시 설명 드리면 화면단에서 현재 뿌려진 마지막 글에 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. 한방 쿼리로 처리할수 있는 방법 있을까요??

by 주킹 [2017.04.26 12:46:24]

질문의 의도가 어렵네요

어떤 database에서 test하신건지..

어떤 결과값을 원하시는지 좀 더 자세한 설명이 필요할 듯 합니다.

올려주신 쿼리로만 봐서는 되는거 같네요


by 쫀득이 [2017.04.26 13:41:21]

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              |
----------------------------------------------------------------------


by 마농 [2017.04.26 13:05:21]

굳이 no 를 만들어서 no 로 처리하려 하지 마시고
그냥 ord 로 처리하시면 될 듯요.


by 쫀득이 [2017.04.26 13:51:03]

음.... 마농님 말씀을 이해 못하겠어요.. ㅠ.ㅠ


by 마농 [2017.04.26 13:57:52]

원 질문글만 보고 답변드린 것입니다.
원 질문글이 실제 내용과 많이 다르네요.
위 답글은 무시하세요.


by 마농 [2017.04.26 13:55:34]

1. 페이징 처리의 정렬기준은 유일해야 합니다.
 - 정렬기준 항목 reply_count 가 Unique 하지 않네요.
 - 정렬기준에 reply_count 외에 review_seq 를 추가하세요.
2. 마지막 seq 를 이용한 next 페이지 구현은
 - 페이징 쿼리의 성능 개선을 위한 방법입니다.
 - 이 경우 키값등을 이용하여 인덱스 스캔을 유도해야 하는데
 - 위 경우엔 키값이 아닌 reply_count 를 이용하여 정렬하네요.
 - 이 경우엔 마지막값을 이용한 next 페이지 구현은 의미 없어 보입니다.
 - 오히려 성능만 더 떨어질것 같네요.
3. 실제 목록쿼리와는 전혀 상관 없는 서브쿼리가 두개나 붙어 있네요.
 - 이걸 왜? 목록쿼리에 붙였는지?
 - 별도 쿼리로 빼길 권합니다.
4. 페이징 쿼리 비효율 제거
 - 조인 및 함수 사용 후 페이징 하지 마시고
 - 조인 및 함수 사용은 페이징 처리 이후로 미루세요.


by 마농 [2017.04.26 14:40:33]

1. 하나의 쿼리로 3가지 정렬조건을 모두 적용하려는 것으로 보이네요.
 - 정렬 기준별 3개 쿼리를 따로 작성하는게 좋습니다.


2. 위에서 언급했던 목록과 전혀 상관 없는 쿼리는
 - 쿼리만 보고 판단했는데 작성하신 쿼리가 잘못된 것 같네요.
 - 상관이 있는 쿼리인데 상관 없게 작성한 듯 하네요.
 - 서브쿼리 favorite_count 부분에 상관관계 조건이 빠졌네요.


by 쫀득이 [2017.04.26 15:23:56]

마농님 정말 답변 감사 합니다.

지적 해주신데로 제가 서브쿼리를 잘못 작성했네요;;; ㅎㅎ

정렬 기준별로 쿼리를 따로 작성하는건 생각 못해봤네요 이 방법으로 조인 전에 페이징 처리가 가능한지 생각해 봐야 겠네요

알려주신 가이드 대로 다시 고민 해보겠습니다  매번 감사 합니다 ㅎㅎ

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