테스트 데이터베이스에 250K 개의 행이있는 테이블이 있습니다. (생산에는 수억 대가 있으며, 동일한 문제를 관찰 할 수 있습니다.)이 테이블에는 고유 인덱스가있는 nvarchar2 (50) 문자열 식별자가 null이 아니라 (PK가 아님) 있습니다.
식별자는 테스트 데이터베이스에서 8 개의 다른 값을 가진 첫 번째 부분 (및 프로덕션에서 약 천 개), @ 기호 및 마지막으로 1-6 자릿수의 숫자로 구성됩니다. 예를 들어 'ABCD_BGX1741F_2006_13_20110808.xml @'로 시작하는 5 만 개의 행이있을 수 있으며 그 뒤에 5 만 개의 다른 숫자가옵니다.
식별자를 기반으로 단일 행을 쿼리하면 카디널리티가 1로 추정되고 비용이 매우 낮아서 잘 작동합니다. IN 표현식 또는 OR 표현식에 여러 식별자가있는 둘 이상의 행을 쿼리하면 인덱스에 대한 추정이 완전히 잘못되어 전체 테이블 스캔이 사용됩니다. 힌트를 사용하여 인덱스를 강제 실행하면 매우 빠릅니다. 전체 테이블 스캔은 실제로 훨씬 느린 속도로 실행됩니다 (생산 속도가 훨씬 느립니다). 최적화 문제입니다.
테스트로, 동일한 DDL과 동일한 내용으로 동일한 스키마 + 테이블 스페이스에서 테이블을 복제했습니다. 좋은 측정을 위해 첫 번째 테이블에서 고유 인덱스를 다시 작성하고 복제 테이블에서 정확히 동일한 인덱스를 작성했습니다. 나는했다 DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);
. 색인 이름이 연속적임을 알 수도 있습니다. 이제 두 테이블의 유일한 차이점은 첫 번째 테이블은 디스크에 흩어져있는 블록 (다른 여러 큰 테이블과 함께 테이블 공간에 있음)과 함께 오랜 시간 동안 임의의 순서로로드되고 두 번째 테이블은 배치 된 것으로로드 된 것입니다 삽입 선택. 그 외에는 어떤 차이도 상상할 수 없습니다. (원래 테이블은 마지막 큰 삭제 이후 축소되었으며 그 이후에는 단일 삭제가 없었습니다.)
병자와 복제 테이블에 대한 쿼리 계획은 다음과 같습니다 (검은 브러시 아래의 문자열은 그림 전체에서 동일하며 회색 브러시 아래에 있습니다).
(이 예에는 검정색 브러시로 표시된 식별자로 시작하는 1867 개의 행이 있습니다. 2 행 쿼리는 1867 * 2의 카디널리티를 생성하고 3 행 쿼리는 1867 * 3의 카디널리티를 생성합니다. 우연의 일치, 오라클은 식별자의 끝을 신경 쓰지 않는 것 같습니다.)
이 문제의 원인은 무엇입니까? 프로덕션 환경에서 테이블을 재생성하는 것은 비용이 많이 듭니다.
USER_TABLES : http://i.stack.imgur.com/nDWze.jpg USER_INDEXES : http://i.stack.imgur.com/DG9um.jpg 스키마와 테이블 스페이스 이름 만 변경했습니다. 테이블 및 인덱스 이름이 쿼리 계획 스크린 샷과 동일 함을 알 수 있습니다.