인덱스에 대한 개념 질문있습니다. 1 10 2,500

by 김포개발자 [Oracle Tuning] [2012.02.07 11:34:53]


안녕하세요 항상 오라클클럽에 도움받는 초보입니다.

쿼리속도가 너무 느려서 이번에 인덱스를 몇개 더 추가하려고하는데,

제가 인덱스에 대한 개념이 없네요

1. 인덱스는 where조건에서만 적용되는게 맞져~?

2. 예를들어 Create index_table(id, datetime) 을 한 후에

select * from 
where id > 0
and datetime = '20120207'

과 같이 한 where 조건에 2개를 동시에 썼을때만 인덱스가 적용 되는게 맞는건가요?

위와 같이 Create index후에 

select * from 
where datetime = '20120207'
과 같이 id를 같이 안쓰고 datetime만 where에 걸면 인덱스가 안걸리는건지가 궁금합니다..

by 부쉬맨 [2012.02.07 11:44:45]
말씀하신내용은 맞습니다.
인덱스가 걸리는지 안걸리는지는 플랜보시면 될꺼같고요.

제가 이런경우 경험상 걸리긴하는데 어느 한쪽 데이터의 양에 따라서
인덱스가 안타고 타는경우를 보았습니다.

옵티마이저의선택이긴하지만요.
근데 대부분 탈꺼라고 봅니다.

굳히 인덱스를 둘중 하나를 많이 사용한다면 하나만 만드시는것도좋고
아님 두개를 같이사용하는경우가 있다면

idx01 에는 datetime만 idx02에는 id, datetime 이런식으로 사용하는방법도하나입니다.

그럼수고하세요.

by 김포개발자 [2012.02.07 11:53:26]
부쉬맨님 답변 감사합니다
많은 도움이 되었어요^^

by 마농 [2012.02.07 12:54:04]
1. 인덱스는 where조건에서만 적용되는게 맞져~?
=> 아닙니다. 여러 방면에서 활용됩니다.
2. where 조건에 2개를 동시에 썼을때만 인덱스가 적용 되는게 맞는건가요?
=> 아닙니다. 하나만 줘도 탑니다.
3. where id > 0 and datetime = '20120207'
=> 이경우 선두컬럼 조건이 이퀄조건이 아닙니다.
이 때는 인덱스를 타긴 타지만 두번째 항목은 인덱스 탐색이 아닌 인덱스 필터로만 이용됩니다.
또한 조건이 0 보다 큰 조건이라면 결국 모든 아이디에 해당한다는 의미이므로
인덱스를 타는게 오히려 풀스캔보다 느리게 될수도 있습니다.
따라서 선두컬럼 조건을 줬다고 해서 반드시 인덱스를 탄다고 보장할 수 없습니다.
4. id를 같이 안쓰고 datetime만 where에 걸면 인덱스가 안걸리는건지?
=> 일반적으로 선행컬럼 조건이 없다면 인덱스 안탑니다.
다만, 인덱스 스킵 스캔 방식이 있어 인덱스를 탈 수도 있습니다.

결론은...
섣부른 일반화의 오류를 범하시면 안됩니다.
여러가지 디테일한 상황마다 결과가 다릅니다.(그때 그때 달라요)

by 김포개발자 [2012.02.07 14:22:58]
헉 너무나 자세한 답변 감사드립니다 마농님,,,
항상 이해하기 쉽게 자세하게 설명해주시는 마농님께 감사드립니다.

by 질문자 [2012.02.08 13:13:06]
조금 헷갈리는게 있어서 질문드립니다.

2번과 4번 답변해주신게 조금 헷갈려서요,
그럼 만약 다음과 같이 datetime을 선행컬럼으로 두고
Create index_table(datetime, id)

select * from
where datetime like '20120208%'
-- and id = 1 <-- 이 조건이 없어도 인덱스가 가능한지,,

로 조회하면 인덱스를 타게 된다는 말씀이신가요?


by 질문자 [2012.02.08 13:14:44]
아니면 일반적으로는 인덱스를 안타지만
스킵스캔방식이나 어떤 힌트를 줘서
datetime+id 의 결합인덱스를 datetime의 단일 인덱스 조회가 가능한건가요~?

by 마농 [2012.02.08 13:28:09]
선행 컬럼 조건만 줘도 인덱스 탑니다.

예를 들어 c1, c2, c3 로 구성된 인덱스라 할때
조건은 이퀄조건으로 가정합니다.
c1 조건만 주면 인덱스 탑니다.
c1, c2 조건도 인덱스 탑니다.
==>c1, c2 모두 인덱스 검색에 사용됩니다.
c1, c3 조건도 인덱스 탑니다.
==> 단, 이때 c2 가 없으므로 인덱스 스캔 범위는 c1의 범위를 모두 스캔하고 c3 는 조건 체크용으로만 사용됩니다.
c2, c3 조건은 인덱스 못탑니다.
==> 선두컬럼 조건이 없으므로
c1은 범위조건 c2도 조건이 주어진다면?
=> c1은 인덱스 검색조건이 되지만 c2는 체크조건만 됩니다.
c1 이퀄조건, c2 범위조건, c3 조건이 주어진다면?
=> c1, c2는 인덱스 검색조건이 되지만 c3는 체크조건만 됩니다.

여기까지는 일반적으로 통용되는 규칙기반으로 설명 드린것이고...
비용기반으로 본다면 인덱스 탈 수도 있고 안탈 수도 잇습니다...
한마디로 복잡합니다.

단순하게 인덱스 타냐? 안타냐?에 집중하시기보다는...
인덱스의 개념정리부터 하셔야 합니다.
기본 개념 정리만 되면 질문하신 부분은 자연스래 해결됩니다.
정답이 없다는 것을 알게 되는 것이 최종 목표가 되겠습니다.

by 질문자 [2012.02.08 13:31:20]
아 감사합니다 인덱스의 개념부터 정리하고 들어가야할것같해요
설명해주신 내용은 너무 이해 잘됐습니다,
언제한번 술이라도 한번 대접하고 싶네요;
감사합니다

by 손님 [2012.02.10 14:27:01]
많은 분들께서 이야기 하셔서 할말은 없지만 저도 아는만큼만...
Create index_table(id, datetime) 로 인덱스를 만들었을 때
선행컬럼은 id가 됩니다. 이때 선행컬럼은 =로 조회하는것이 좋습니다.
반대로 말하자면
select * from
where id > 0
and datetime = '20120207'
이 쿼리에서는 Create index_table(datetime, id) 이렇게 생성하는것이
유리합니다.
그리고 인덱스 만든것이 Unique index라면 datetime = '20120207' and id = 3
이런식으로 하면 index unique scan이 적용되지만 위 쿼리처럼 부등호를 하게 되면
index range scan이 될것입니다.
또 datetime = '20120207' 이조건만 준다면 range scan이 될 확률이 많습니다.
그리고 9i 이하버전에서는 반드시 선행컬럼이 =조건이 되야 인덱스를 타고
10g부터는 선행컬럼이 =이 아니여도 skip scan이 된다고 합니다.
하지만 10g에서도 선행컬럼의 분포도가 나쁘다면(distinct 했을 때 나오는
row의 수가 많을수록 나쁨) skip scan이 실행되지 않을수 있습니다.
이유는 첫번째 범위의 조건의 너무 방대하기 때문입니다.
따라서 이때는 range scan이나 full table scan의 실행계획이 될수도 있습니다.

by 질문자 [2012.02.14 14:06:14]
손님님 답변 늦게 보고 감사의 말씀 드립니다.
너무 상세하게 말씀해주셔서 너무 감사드려요
답변달아주신분들 덕에 인덱스의 개념에 대해서 확실히 알게 되었어요
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입