테이블 조인시 카운트 성능 저하 질문입니다. 0 7 4,052

by 콩이 [DB 모델링/설계] 조인 테이블 카운트 성능 [2012.11.06 10:27:15]


안녕하세요. 지난번에 마농님 덕분에 상당한 진전을 보았습니다. 마농님께 감사드리고, 많은 고수님들께도 감사드립니다.

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

'그룹' 테이블
번호 | 그룹명 | 등록자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만건 정도
될거라서요.. 

조언부탁드려요 ㅜㅜ
by 신이만든짝퉁 [2012.11.06 10:58:53]
1. 카운트시 인덱스 힌트 대신에  parallel 힌트를 사용해보세요.

2. 아니면, 힌트 자체를 빼고 해보세요. 풀스캔이 빠를 수 있습니다.

3. 별도의 카운트 테이블(그룹아이디, 카운트)을 만들어, 이 테이블과 조인하여 조회하는 것을 고려해보세요.
   트리거를 통해 카운트 테이블을 업데이트하면 될 것 같습니다.

by Oracler [2012.11.06 11:01:00]
인덱스 정보는 어떻게 되나요?

by 콩이 [2012.11.06 11:23:19]

그룹상세 테이블 인덱스
-기본키
CREATE UNIQUE INDEX IPK_T_ADDR_DETAIL
ON T_ADDR_DETAIL (NO)
-별도 인덱스
CREATE INDEX PK_T_ADDR_DETAIL01
ON T_ADDR_DETAIL (USER_ID, NO)

그룹 테이블 인덱스
CREATE UNIQUE INDEX PK_T_ADDR_GROUP
ON T_ADDR_GROUP (NO)

로 되어 있습니다.

by 마농 [2012.11.06 12:44:57]
T_ADDR_DETAIL (USER_ID, PARENT_NO) 가 필요합니다.

by 콩이 [2012.11.06 13:16:55]
감사합니다. 그럼 기존 T_ADDR_DETAIL (USER_ID, NO) 를 지우고
T_ADDR_DETAIL (USER_ID, NO, PARENT_NO)으로 새로 만들어야 할까요?

by 마농 [2012.11.06 13:25:33]

T_ADDR_DETAIL (USER_ID, PARENT_NO) 가 좋을 듯 합니다.


by 콩이 [2012.11.06 13:37:14]
예 감사합니다.^^
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입