테이블 조인시 index 안타는 문제..(분포도 때문으로 예상) 0 9 6,984

by sam [SQL Query] index 분포도 join [2013.01.24 11:28:07]



안녕하세요.  한참 눈팅만 하다가 처음 질문 올려봅니다.. ^^;

A와 B 두 테이블 조인하는데 자꾸 두 테이블 다 풀스캔이 뜹니다..

구조는 아래와 같습니다.

-구조-

A테이블 컬럼
idx number
idx2 varchar2(4)
value varchar2(200)

키,인덱스
PK_A (idx, idx2) - pk, 유니크인덱스
INDEX_A_01 (idx) - 인덱스

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

B테이블 컬럼
idx number
value varchar2(200)

키,인덱스
PK_B ( idx ) - pk, 유니크인덱스


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

-쿼리-

select * from a, b
where a.idx = b.idx


-Plan-
SELECT STATEMENT  ALL_ROWS Cost: 57  Bytes: 2,354,472  Cardinality: 11,106    
3 HASH JOIN  Cost: 57  Bytes: 2,354,472  Cardinality: 11,106   
 1 TABLE ACCESS FULL TABLE B Cost: 21  Bytes: 178,050  Cardinality: 1,187 
 2 TABLE ACCESS FULL TABLE A Cost: 35  Bytes: 688,572  Cardinality: 11,106 


위 쿼리로 plan과 같이 풀스캔이 됩니다.

개발DB밖에 접속이 안되는데 데이터는 a테이블 1만여건 b테이블 1천여건입니다.
운영DB는 아마도 a테이블 200만건이상, b테이블 4천건 정도로 예상됩니다. (운영DB를 볼 수가 없음..)

제가 생각은 데이터가  적어서 인덱스 컬럼의 분포도 때문에 풀스캔하는 것 같은데요.
이상한 점은 조인할 때 b테이블 드라이빙 할 때 적어도 b테이블의 idx는 index fast full scan 이 떠야 되는거 아닌가요??

질문을 정리해보겠습니다.
1. 위 상태에서 a,b 둘다 풀스캔 하는 이유
2. 분포도 문제라면 운영DB의 데이터가 위 설명대로 일 때 풀스캔하는거 무시하고 위와 같이 조인하면 인덱스를 잘 탈지
3. 분포도 문제일 경우 이런경우에는 어떻게 처리하는게 올바른지..

DBA가 풀스캔에 엄청나게 민감하기 때문에.. 걱정 되서 올립니다.. 잘좀 부탁드릴게요..^^

1번만 답변해주셔도 됩니다... 잘부탁드려요 꾸벅

by 이재현 [2013.01.24 13:10:26]

아.. 머부터 설명을 해야하나.. ㄷㄷ

다 배제 하고 위 사황만 설명드리겠습니다.

우선 인덱스에 조건이 없어서 인덱스를 타지 않았습니다.

그럼으로 풀 스캔을 유발하니 옵티마이저는 해시로 조인을 선택하였습니다.

해시 조인은 작은 테이블을 먼저 드리아빙( 빌트인 ) 시키는게 유리한데 잘못된 통계정보로 인하여

B 테이블으 먼저 드라이빙하게 되었습니다.

B Cost: 21 Bytes: 178,050 Cardinality: 1,187

by 마이신 [2014.04.04 17:13:51]
안녕하세요.. 저도 위 상황과 비슷한 문제가 있어..

여기 저기 기웃거렸는데요..

님 말데로.. 조건을 걸어주니.. 인덱스를 타게되더군요..^^;
좋은거 배웠내요~~ 감사합니다.

by sam [2013.01.24 13:19:53]

그럼 위 상황에서 인덱스 태우려면 어케해야되나요 .
인덱스 조건이 없어서 인덱스를 안탄다는 부분이 이해가 잘안됩니다...
a랑 b테이블에 idx 컬럼을 인덱스 생성하였는데 잘못 생성한건가요 ?
잘못된 통계정보에 대한부분도 알기쉽게 말씀해주시면 감사하겠습니다 ㅜ

by 부쉬맨 [2013.01.24 13:32:14]

1. 위 상태에서 a,b 둘다 풀스캔 하는 이유
  -> 특정조건이없이 두개를 조인형태이므로? count라든지 한다면 index full scan 타겠네요 10g이상이라면... 

2. 분포도 문제라면 운영DB의 데이터가 위 설명대로 일 때 풀스캔하는거 무시하고 위와 같이 조인하면 인덱스를 잘 탈지
  -> 제대로된 인덱스, sql을 짜는 수준 에 따라서 타겠죠?

3. 분포도 문제일 경우 이런경우에는 어떻게 처리하는게 올바른지..

DBA가 풀스캔에 엄청나게 민감하기 때문에.. 걱정 되서 올립니다.. 잘좀 부탁드릴게요..^^
-> 왜 풀스캔에 대해서 민감하냐고 물어보세요. 풀을 타야좋을경우도분명있을텐데...


select * from a, b 
where a.idx = b.idx
   and a.idx > ' ' 

예전에 통계정보가 없을때 이렇게 꼼수로 해서 사용하긴했었는데..10g이상은 
잘모르겠네요..-_-;;


by sam [2013.01.24 13:47:07]
이재현//
답변해주신 내용중
해시조인시 작은 테이블을 먼저 드라이빙 해야한다고 하셨잖아요..

B 테이블으 먼저 드라이빙하게 되었습니다.
B Cost: 21 Bytes: 178,050 Cardinality: 1,187

이거

b테이블이 4천건 a테이블이 1만건인데  b테이블 부터 드라이빙 됐으니
맞는거 아닌가요??
plan에 1 에 b테이블 2에 a테이블이면  b테이블을 풀스캔 한 후에 조인 한거 같은데.. 제가 잘몰라서 ;

by 마농 [2013.01.25 09:12:51]

인덱스와 조인의 수행원리를 모른채...
풀스캔 탄다고 해서, 인덱스 안탄다고 해서 나쁜게 아닙니다.
인덱스 스캔은 인덱스 스캔 후에 테이블을 랜덤엑세스 하게 되는데 싱글블럭IO방식으로 읽습니다.
소량의 경우엔 문제 없겠지만 데이터가 많으면 이게 오히려 부담이 됩니다.
해쉬로 풀린다면 문제 없는것. 정상인듯 합니다.
인덱스가 유용한 경우는 전체 자료중 일부자료를 검색할때 유용한 것이지
전체 자료를 모두 검색하는데는 풀스캔이 유리합니다.


by 이재현 [2013.01.25 15:58:11]
아.. 죄송합니다. ㅠ

운영에 4천만건이 아니고 4천건이군요.. ㅎㅎ

개발에 B란 테이블이 1천여건이라면 현재 테이블 통계정보는 나름 정확하다고 볼수 있습니다.

--근거
B Cost: 21 Bytes: 178,050 Cardinality: 1,187

1. 위 상태에서 a,b 둘다 풀스캔 하는 이유

select * from a, b
where a.idx = b.idx

술어절에 인덱스 컬럼에 조건이 없고 전체를 이퀄 조인이 발생하는 쿼리입니다.

그럼 당연이 전체를 다 읽어야 하죠?? 

그래서 풀스캔을 옵티마지어가 선택하였습니다.

물론, 인덱스 스캔이 효율적인데 옵티마이저가 풀스캔으로 선택하는 경우가 있습니다.

이런 경우는 9i 이전

 고스트( COST : 아이오카운터 ) = 싱글블럭아이오 카운터 + 멀티 블럭아이오 카운터

으로 비용을 계산하는데 만약 잘못된 통계정보에의해 전체 카드널리는 작은것( 한번에 읽어올수 있는 멀티블

럭 아이오 카운터 : 1  ) 으로 판단하고, 싱글블록 아이오 카운터도 1이라면.. 옵티마이저는 멀티블럭아이오를 

선택합니다. 왜냐? 싱글블록아이오 카운터가 1에다가 테이블에 해당하는 컬럼이 존재하면 그 랜댐엑세스 비용

이 가중이 되니 9i 이전( 포함 ) 부터는 멀티블럭 아이오( 풀스캔, 인덱스 페스트 풀스캔 ) 선택하는 잘못된 

실행계획을 선택하는 경우도 있지만 요즘 사이트 따라 워낙 슈퍼급 OS에 메모리 256 까지 가는 사이트도 봤

었는데 이때는 머가 좋은지는 장담 못합니다.

물론 최적의 실행계획은 최적의 비용을 가지고 최대의 성능을 만드는다는 논리로 애기하면..

싱글블록이 필요한 곳은 싱글블록... 멀티블록이 필요한곳은 멀티블록... 경우에 따라 틀리다고 판단합니다.

나머지 자세한 사항은 OOO( 옵티마징 오라클 옵티마이저 ) 라는 책을 보세요( 아 물론 10g 이후는 비용 계산이 틀립니다. )

아. 애기가 중간에 빠져는데.. 전체를 조인으로 풀리는 쿼리이니 옵티마지어는 풀스캔을 선택할수 밖에 없는 상

황입니다.

여기서 풀스캔도 종류가 있습니다.

   인덱스 패스트 풀스캔 - 멀티블럭아이오( 보통 64k )
   인덱스 풀스캔 - 싱글블럭아이오( 보통 8k )
   테이블 풀스캔 - 멀티블럭이오( 보통 64k )

인데스 페스트 풀스캔으로 풀린다면 이후 테이블 스캔을 또 하여야 합니다. 비용 : 64... + ( 8... )

인덱스 풀스캔 이후 테이블 스캔을 또 하여야 합니다. 비용 ( 8... ) + ( 8 ... )

테이블 풀스캔 비용 ( 64... )

10g의 비용( COST ) = 싱글블록아이오카운터 + 조정된 멀티블록아이오카운터 + 조정된 CPU 사용량

대충 이정도로 애기드리고 자세한 사항은 책을 보세요

위 사항에서 어떻게 가장 효율적인가요?? 3번입니다. 물론 싱글블록아이오 보단 비용을 높여놓긴 했지만...

어짜피 읽을거 한거번에 테이블 플스캔으로 읽어 버리는게 가장 효율적이라

테이블 풀스캔을 선택하였습니다.

2. 분포도 문제라면 운영DB의 데이터가 위 설명대로 일 때 풀스캔하는거 무시하고 위와 같이 조인하면 인덱스를 잘 탈지

우선 답은 아닙니다.

인덱스 컬럼에 (아마) 아주 우수한 분포도를 존재하지만 해당 컬럼에 선택했을시 효과를 발휘합니다.

상식적으로 생각을 해보시면.. 분포다가 우수하다고 해서 선택을 하지 않으면.. 어짜피 전체을 읽어야합니다.

아래와 같은 경우는 인덱스 스캔이 아주 효율적이겠죠.

물론 아래와 같은 경우라면 옵티마지어는 인덱스 스캔과 NL 조인을 선택하였을 겁니다.

select * from a, b
where a.idx = b.idx
    AND A.IDX = :BIND_IDX

3. 분포도 문제일 경우 이런경우에는 어떻게 처리하는게 올바른지..

select * from a, b
where a.idx = b.idx

이런 쿼리라면 풀스캔이 제일 유리합니다.

2) 의문

그런데 예시쿼리는 테스터 쿼리이고 실무에선 다른쿼리를 사용하지  않나요??

3) 문제점

PK_A (idx, idx2) - pk, 유니크인덱스
INDEX_A_01 (idx) - 인덱스

4) 결론

해당 사이트에 DBA 분이 풀스캔을 엄청나게 민감하게 생각하는 경우라도 예시 쿼리는 어쩔수 없이 풀스캔이 타니..

SQL 튜닝요청을 하세요~

PS. 댓글다시 모든분들도 말씀도 고민하셔야합니다.


by 손님 [2013.01.26 05:32:52]

아 잘못 설명드렸습니다.

싱글아이오 카운터 = 1,  멀티블럭아이오 카운터 = 1 이라면 멀티블럭아이오을 선택할 확율이 높습니다.

by sam [2013.01.28 14:46:59]

자세한 설명 감사드립니다.  아주 많은 도움이 되었습니다.^^ 답변채택이 늦어졌네요..

마농,이재현님 그리고 다른분들도 답변 감사드립니다.
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입