문제

이 테이블이 있습니다.

create table demo (
    key number(10) not null,
    type varchar2(3) not null,
    state varchar2(16) not null,
    ... lots more columns ...
)

그리고이 지수 :

create index demo_x04 on demo(key, type, state);

이 쿼리를 실행할 때

select * from demo where key = 1 and type = '003' and state = 'NEW'

EXPLAIN PLAN 전체 테이블 스캔을 수행 함을 보여줍니다. 그래서 나는 색인을 삭제하고 다시 만들었습니다. EXPLAIN PLAN 여전히 전체 테이블 스캔이 표시됩니다. 어떻게 그렇게 될수 있니?

일부 배경 : 이것은 역사적 데이터이므로, 상태와 함께 행을 찾는 것입니다. CLEARED 상태와 함께 새 행을 삽입하십시오 NEW (또한 이전 행에서 몇 가지 값을 복사합니다). 그런 다음 이전 행이 업데이트됩니다 USED. 그래서 테이블은 항상 자랍니다. 내가 알아 차린 것은 인덱스의 카디널리티가 0이라는 것입니다 (수천 가지 값이 있다는 사실에도 불구하고). 재현 후 카디널리티가 커졌지 만 CBO는 지수를 더 좋아하지 않았습니다.

다음날 아침, 오라클은 갑자기 색인을 좋아했고 (아마도 그 위에 잤을 것입니다) 사용하기 시작했지만 오래 사용하지 않았습니다. 잠시 후, 처리는 50 행/s에서 3 행으로 떨어졌고 "전체 테이블 스캔"을 다시 보았습니다. 무슨 일이 일어나고 있습니까?

제 경우에는 약 백만 행을 처리해야합니다. 나는 ca. 50. 인덱스를 업데이트/재개하겠다고 커밋 한 후에 실행 해야하는 명령이 있습니까?

나는 Oracle 10G에 있습니다.

편집]이 표에는 969'491 개별 키, 3 개의 유형 및 3 개의 상태가 있습니다.

도움이 되었습니까?

해결책

인덱스 힌트를 지정하면 어떻게됩니까? 이 시도:

SELECT /*+ INDEX (demo demo_x04) */ * 
  FROM demo 
 WHERE key = 1 
   AND type = '003' 
   AND state = 'NEW';

밤새 일어난 일은 테이블이 분석되었다는 것 같습니다. 그런 다음 테이블에 대한 처리를 실행하면서 Oracle의 테이블 통계가 다시 부실하게 만들기 위해 충분한 인덱스가 업데이트되었고 Optimizer는 인덱스 사용을 중단했습니다.

힌트를 추가하고 설명 계획이 다른 계획을 제공하고 쿼리가 더 잘 수행되는지 확인하십시오.

오, 그리고 테이블 분석에 관한 Tony의 답변은 일반적인 모범 사례이지만, 10G는 데이터베이스가 그와 관련하여 자기 유지 보수를하는 데 매우 좋습니다. 프로세스가 많은 업데이트를 수행하면 색인이 빨리 오래 될 수 있습니다. 프로세스가 시작될 때 분석을 실행하면 상황이 한동안 개선되면 이것이 문제라는 것을 알게 될 것입니다.

테이블에 대한 통계를 업데이트하려면 dmbs_stats.gather_table_stats 패키지.

예를 들어:

exec dbms_stats.gather_table_stats ( '소유자', '데모');

다른 팁

최근에 테이블이 분석 되었습니까? Oracle이 그것이 매우 작다고 생각하면 인덱스 사용을 고려하지 않을 수도 있습니다.

이 시도:

select last_analyzed, num_rows 
from user_tables
where table_name = 'DEMO';

Num_rows는 Oracle이 테이블에 포함 된 몇 개의 행 수를 알려줍니다.

"다음날 아침, 오라클은 갑자기 지수를 좋아했습니다 (아마도 그 위에 잤을 것입니다)"아마도 DBMS_STATS가 밤새도록 실행 중일 것입니다.

일반적으로 나는 색인을 전체 테이블 스캔 한 세 가지 이유 중 하나를 볼 수 있습니다. 첫 번째는 Optimizer가 테이블이 비어 있거나 적어도 매우 작다고 생각한다는 것입니다. 나는 이것이 초기 문제라고 생각합니다. 이 경우 인덱스를 사용하기보다는 소수의 블록으로 구성된 테이블을 전체 스캔하는 것이 더 빠릅니다.

두 번째는 쿼리가 인덱스를 실제로 사용할 수없는 경우입니다.

"select * from demo where key = 1 and type = '003' and state = 'NEW'"

실제로 쿼리에서 하드 코딩 된 리터럴을 사용하고 있습니까? 그렇지 않은 경우 변수 데이터 유형이 잘못 될 수 있습니다 (예 : 키는 문자). 이는 숫자 키를 비교를 위해 문자로 변환해야하므로 색인이 거의 쓸모가 없게됩니다.

세 번째 이유는 쿼리가 테이블의 많은 행을 처리 할 것이라고 생각하는 곳입니다. 유형과 상태는 카디널리티가 매우 낮아 보입니다. 특정 '키'값이 많습니까?

당신이 설명하는 처리에 대한 의견 : 간헐적 커밋으로 행으로 처리하는 것처럼 들리며, 가능하다면 이것을 다시 생각할 것을 촉구합니다. 업데이트/삽입 메커니즘은 합병 명령문으로 잘 변환 될 수 있으며 전체 데이터 세트는 끝에 하나의 커밋으로 단일 문으로 처리 될 수 있습니다. 이것은 현재 방법보다 거의 더 빠르고 리소스를 적게 사용합니다.

열 키의 값은 항상 1입니까? 그렇다면 각 행을 검사해야하므로 인덱스 컨설팅이 쿼리를 최적화 할 것이라고 확신하지 못합니다. 그렇다면 키 열이없는 색인을 선언하십시오. 당신은 또한 시도 할 수 있습니다 :

select key, type, state from demo where key = 1 and type = '003' and state = 'NEW'

(내 추측이 옳은 경우) 각 행을 계속 살펴 봐야하지만 결과 세트의 모든 열이 이제 덮여 있기 때문에 인덱스로 이동할 수 있습니다.

나는 당신의 진술에 기초하여 인덱스가 카디널리티 0을 보여준다는 것을 추측하고 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top