마농님 다시 한번 더 여쭐게요.. 0 8 2,702

by 콩이 [DB 모델링/설계] 조인 성능 인덱스 [2012.11.06 15:09:54]


우선 제 테이블 상황입니다.

'그룹' 테이블
번호 | 그룹명 | 등록자ID | 날짜
'그룹상세' 테이블

번호 | 부모번호 | 성명 | 핸드폰 | 이메일 | 팩스 | 등록자ID | 날짜

우선 필수조건은
조인시 필요한 그룹테이블 NO(번호)와 그룹상세 테이블 PARENT_NO(부모번호)
그리고 등록자ID 즉 USER_ID 입니다.

그리고 유동적 조건은 그외 '그룹명', '성명', '핸드폰', '이메일', '팩스' 번호입니다.

정렬은 날짜 또는 번호로만 가능하면 될 것 같습니다.

그룹상세 테이블엔 데이터가 약 310만건 정도 있습니다. 예상되는 데이터는 2000만건 정도이구요...
벌써부터 느려지면 안되는데 말입니다.
그리고 그룹상세 테이블은 수정/삭제/삽입이 빈번하게 일어나는 테이블입니다.

---------------------------------------------------------------------------------------------------------------------------------

위와 같은 상황에서 쿼리를 분리하였습니다. 그룹명 검색시와 그룹명 검색이 없을시로 나누었습니다.
상당히 큰 효과가 있었습니다. 그런데 프로그램을 통해 보니 또 느려지는겁니다. 그래서 확인해보니
카운트시에 문제가 있었습니다. 페이징 쿼리를 위해서 검색 조건에 대한 전체 COUNT를 먼저 수행하는
과정에서 느려지더군요.

물론 그룹명 검색시에 테이블 조인을 하다보니, 즉 그룹테이블과 그룹상세 테이블을 묶어서 그룹명 검색을
하고 카운트를 하니, 상당히 느려지는겁니다.

다음은 일반 검색시와 그룹명 검색시의 전체적인 쿼리입니다.

--------------------------------------------------------------------------------------------------------------------------------

-일반검색/카운트
SELECT /*+ INDEX_FFS(NO PK_T_ADDR_DETAIL) */ COUNT(NO) AS CNT FROM T_ADDR_DETAIL WHERE USER_ID =  'test'  

-일반검색/페이징쿼리
SELECT a.name AS group_name
     , b.*
  FROM t_addr_group a
     , (SELECT /*+ INDEX_DESC(b PK_T_ADDR_DETAIL01) */
               ROWNUM AS rnum
             , b.*
          FROM t_addr_detail b
         WHERE b.user_id ='test'    AND B.NAME LIKE '홍길%'
           AND ROWNUM <=10
        ) b
 WHERE a.no = b.parent_no
   AND rnum >= 1
 ORDER BY B.NO desc


-그룹명검색/카운트
SELECT /*+ INDEX(T_ADDR_DETAIL PK_T_ADDR_DETAIL01) */  COUNT(B.NO) AS CNT FROM T_ADDR_GROUP A, T_ADDR_DETAIL B WHERE A.NO = B.PARENT_NO AND B.USER_ID =  'test'

-그룹명검색/페이징쿼리
SELECT *
  FROM (SELECT ROWNUM rnum
             , c.*
          FROM (SELECT A.NAME AS group_name
                     , b.*
                  FROM t_addr_group a
                     , t_addr_detail b
                 WHERE b.user_id = 'test'
                   AND a.name LIKE '테스%'
                   AND a.no = b.parent_no
                 ORDER BY B.NO desc 
                ) c
         WHERE ROWNUM <= 2 * 10
        )
 WHERE rnum >= 2 * 10 - 9
   AND ROWNUM <= 10
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

위와 같이 구성을 했습니다. 특히 그룹검색시 카운트 부분에서 상당히 느려집니다..
좋은 해결방안 조언을 구합니다.
그리고 저렇게 나누는 쿼리 방식에서 더 효율적인 방법이 있을까요? 데이터가 약 2000만건~3000만건 정도
될거라서요.. 

인덱스 정보는 아래와 같습니다.
그룹상세 테이블 : 
T_ADDR_DETAIL (NO)
T_ADDR_DETAIL01 (USER_ID, PARENT_NO) 
그룹 테이블 : 
T_ADDR_GROUP (NO)

------------------------------------------------------------------------------------------



위에까지는 어느정도 처리가 된 상태입니다. 하지만 인덱스를 위처럼 하고 다시 실행해도 카운트시 상당한 시간이 
걸리네요..(그룹명을 검색할 경우에요)

그리고 일반검색쿼리에서도... b.no 즉 그룹상세테이블의 no을 desc 하는데, 먹질 않습니다...

도와주세요..
by 마농 [2012.11.06 16:25:40]
힌트는 빼고 해보셨나요?
그룸명검색 카운트 쿼리에 그룹명 검색조건이 보이질 않는건 왜죠?
실행계획은 확인해 보셨나요?

by 손님 [2012.11.06 16:37:40]


-- 그룹명검색/카운트
SELECT /*+ INDEX(B PK_T_ADDR_DETAIL01) */ 
   COUNT(B.NO) AS CNT
  FROM T_ADDR_GROUP  A
, T_ADDR_DETAIL B
 WHERE A.NO = B.PARENT_NO
   AND B.USER_ID =  'test'
;  

SELECT COUNT(A.NO) AS CNT
  FROM T_ADDR_DETAIL A
 WHERE A.USER_ID =  'test'
   AND EXISTS (SELECT 1 FROM T_ADDR_GROUP WHERE NO = A.PARENT_NO)
;  


by 콩이 [2012.11.06 17:05:16]
그룹명 검색은 오기가 되었습니다. 원래는 있었는데요..
힌트도 빼고 해봐도 그러네요..^^

by 손님 [2012.11.06 17:38:50]

윗분께서 올려주신거 각각 실행계획 한번 올려봐주시면 도움이 될거 같네요

by 마농 [2012.11.06 17:47:13]

제가 생각하는 추천 실행계획은


1. 그룹명 검색 없을 때(b => a)
t_addr_detail(user_id, parent_no) 인덱스에서
user_id 로 인덱스 검색하고, 검색된 인덱스의 parent_no 를 t_addr_group 에 조건으로 제공합니다.
t_addr_group(no) 인덱스를 검색합니다.


2. 그룹명 검색 있을 때(a => b)
t_addr_group(group_name, no) 인덱스에서
group_name 으로 인덱스 검색하고, 검색된 인덱스의 no 를 t_addr_detail 에 조건으로 제공합니다.
검색조건 User_id 와 앞서 인덱스 탐색한 no 의 조합으로
t_addr_detail(user_id, parent_no) 를 검색합니다.


t_addr_group(group_name, no) 인덱스가 있으면 좋겠고
없다고 해도 t_addr_group 전체건수가 많지 않다면 상관 없을듯 합니다.
직접 해볼수 없는 상황에서 생각만으로 답변하니 정답이 아닐 수 있습니다.
우선 실행계획을 확인해 보고 스스로 판단하셔야 합니다.
일단 제가 원하는 실행계획을 위한 힌트는 다음과 같습니다.
SELECT /*+ LEADING(a) USE_NL(b) INDEX(b pk_t_addr_detail01) */ COUNT(*)
  FROM t_addr_group a
, t_addr_detail b
 WHERE b.user_id = 'test'
   AND a.name LIKE '테스%'
   AND a.no = b.parent_no
;


by 마농 [2012.11.06 17:48:18]

아 그리고 왠만하면 인덱스 명칭을 바꾸시는게 좋겟네요...
pk 로 시작하는건 기본키라는 의미를 가지고 있지요.


by 마농 [2012.11.07 09:30:56]

간과한게 하나 더 잇네요.
Index_desc 힌트를 적용하려면 인덱스에 no 가 포함되어야 하겠네요.
t_addr_detail(user_id, no, parent_no)


by 콩이 [2012.11.07 10:56:43]
아 답변을 해주셨군요.. 어제 계속 이거저거 확인해봐도 답이 안나오더라구요..

감사합니다. 정말로..ㅜㅜ

일단 실행계획 해보도록 하겠습니다.

인덱스에 대해 감이 잘 안잡히네요 전 초보라서 ㄷㄷ
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입