2011-07-26 2 views
3

Oracle 10g를 사용하고 있습니다. 여기 내 검색어입니다IN 절 최적화

select * from Entries 
where RefKey in (select RefKey 
       from Entries 
       where KeyStat = 1) 
and RefKey = Key; 

여기에서 RefKey, Key 및 KeyStat 모두 색인이 생성됩니다. 테이블은 여기에서 사용되지 않는 다른 컬럼으로 분할됩니다. 이 쿼리에서 현재 마스터 키 (RefKey = 키, 마스터 인 경우)를 현재 선택합니다 (KeyStat = 1). 다음은 SQLTools 1.21 RC3을 사용하는이 쿼리의 실행 계획입니다.

---------------------------------------------------------------------------------------------------------------------- 
| Id | Operation       | Name   | Rows | Bytes | Cost (%CPU)| Time  | Pstart| Pstop | 
---------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT     |    |  1 | 270 | 218K (1)| 00:43:37 |  |  | 
| 1 | NESTED LOOPS SEMI     |    |  1 | 270 | 218K (1)| 00:43:37 |  |  | 
| 2 | PARTITION RANGE ALL    |    |  1 | 262 | 218K (1)| 00:43:37 |  1 | 12 | 
|* 3 | TABLE ACCESS FULL    | ENTRIES  |  1 | 262 | 218K (1)| 00:43:37 |  1 | 12 | 
|* 4 | TABLE ACCESS BY GLOBAL INDEX ROWID| ENTRIES  | 10M| 77M|  3 (0)| 00:00:01 | ROWID | ROWID | 
|* 5 | INDEX RANGE SCAN     | IND_ENTR_REFKEY|  1 |  |  2 (0)| 00:00:01 |  |  | 
---------------------------------------------------------------------------------------------------------------------- 

나는 "TABLE ACCESS FULL"에 대해 우려하고 있습니다. 이 쿼리에서 사용되는 모든 열이 인덱싱되면 oracle이 전체 테이블 스캔을 수행하는 이유는 다음과 같습니다.

어떻게 최적화 할 수 있습니까? 내부 쿼리에 일부 값을 넣으면 훨씬 빠르게 반환됩니다.


하위 쿼리가 필요한 이유를 설명합니다. 하나 이상의 활성 키가있는 전체 일괄 처리를 선택합니다. Refkey는 고유하지 않습니다. 예를 들면 다음과 같습니다.

Key=1, RefKey=1, Stat=1 
Key=2, RefKey=1, Stat=0 
Key=3, RefKey=2, Stat=1 
+0

나는 이미지를 업로드 할 수 없습니다되었고, 위의 실행 계획 죄송합니다, 올바른 형식 점점되지 않았습니다. – bjan

+0

테이블에서 통계를 수집 해 보셨습니까? –

답변

5

표 ACCESS FULL "나는 3 = ID에 대한 걱정" "모든 열 이 쿼리에서 사용되는 경우 오라클은 전체 테이블 스캔을하는 이유. 다음 인덱싱됩니다."

최적화 프로그램이 KEYSTAT에서 색인을 무시합니다. 나는 KEYSTAT이 매우 선택 적이 지 않고 (비교적 적은 수의 고유 값) 그리고/또는 그 값이 ENTRIES 테이블의 전체 범위에 고르게 분포되어 있기 때문에 이것이 일 것이라고 추측 할 수있다. 쿼리가 테이블의 모든 블록에 거의 다가 가면 FULL TABLE SCAN이 가장 좋은 경로입니다.

이 추측은 하위 쿼리를 필터링하여 속도를 높이면 유효성이 확인됩니다.

다른 사람들이 제안한 것처럼 하위 쿼리를 제거하기 위해 문을 리팩터링하는 것이 성능을 향상시키는 가장 좋은 방법입니다.


"KeyStat = 0, 단지 몇 1000에 그렇게 도움이 될 것 인덱스를 사용하여 1이있을 것이다 가진 수백만 개의 항목이있을 것"이라고 말했다.

왜곡 된 데이터 분포는 종종 성능 문제의 원인입니다. 데이타베이스 이 KEYSTAT = 1이 KEYSTAT = 0보다 훨씬 더 선택 적이라는 것을 모릅니다. 우리가 말하지 않는 한, 당신은 그 인덱스에 대한 통계를 수집 할 때 히스토그램을 생성하는 것을 고려해야 할 것입니다. Find out more.

히스토그램은 특히 리터럴의 바인드 변수를 사용하는 쿼리를 사용할 때 문제를 일으킬뿐만 아니라 문제를 일으킬 수 있습니다. 따라서 생산에 투입하기 전에 샌드 피트 (sandpit)에서 벤치마킹하십시오.

+0

KeyStat = 0을 가진 수백만 개의 항목이 있고, 1000s에있는 항목이 1 개 밖에 없으므로 색인을 사용하면 유용합니다. 예를 들어 내가 가지고있는 샘플 DB는 1이있는 레코드가 5 개 뿐이고 20105126은 0 – bjan

4

아마도 내가 누락되었지만 동일한 결과가 나오지 않아야합니까?

select * 
from Entries e 
where e.KeyStat = 1 
    and e.RefKey = e.Key 
1

당신은

EXPLAIN PLAN FOR select * from Entries 
where RefKey in (select RefKey 
       from Entries 
       where KeyStat = 1) 
and RefKey = Key; 

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); 

당신은이 끝에 추가 정보의 무리와 함께 계획을 설명 할 수 있어야 할 수 있습니다. 특히, 당신은 그 작업에 관심이 있습니다 3. 전체 테이블 스캔을하는 것뿐만 아니라 행/카디널리티를 1로 지정하는 것입니다. 실제로는 아무것도 찾지 않을 것이라고 생각합니다. 거기에 0의 값을 준다). 당신은 그것을 작동 4 약 10 만 행을 이야기하지만, 때문에 지금까지 행을 찾을 것을 기대하지 않는 것을 알 수 있습니다

, 그것은 '3'과 그 '2'인덱스 비용의 비용을 제공합니다. '3'의 스캔이 아무것도 찾을 수 없으므로 인덱스 스캔에 값을 입력 할 것으로 예상하지 않으므로 10M 행을 볼 수 없습니다.

그래서 두 가지 문제점이 있습니다. 첫째, KeyStat의 인덱스를 사용하지 않습니다. 두 번째로, 일치로 반환되는 행 수를 과소 평가합니다. 첫 x 째는 데이터 유형 불일치로 인해 _ 생했을 수 있습니다. 아마도 KeyStat은 문자 값입니다. 어쩌면 인덱스의 주요 컬럼이 아닐 수도 있습니다. 어쩌면 색인이 사용 불가능하게되었을 수도 있습니다 (ETL 작업 중?).

이상한 추정치도 암시 적입니다. 열이 색인의 선행 열인 경우 열의 max_val이 1 인 통계가 효과가 있다고 기대할 수 있습니다. max_val이 0이라고 생각하면 "찾을 수 없습니다. 아무것도 "견적하지만 max_val을 빨리 찾기 위해 사용할 색인이 없었습니다.