문제

쿼리 1에서는 ID가 인덱스된 열임에도 불구하고 전체 테이블 스캔이 수행됩니다.쿼리 2는 동일한 결과를 얻지만 훨씬 더 빠릅니다.인덱싱된 열을 반환하는 쿼리 1을 실행하면 빠르게 반환되지만 인덱싱되지 않은 열이 반환되거나 전체 행이 반환되는 경우 쿼리 시간이 더 오래 걸립니다.

쿼리 3에서는 빠르게 실행되지만 'code' 열은 NUMBER(12) 대신 VARCHAR2(10)이고 'id'와 동일한 방식으로 인덱싱됩니다.

쿼리 1이 인덱스를 사용해야 한다는 사실을 인식하지 못하는 이유는 무엇입니까?인덱싱된 숫자 열이 더 빠르게 수행될 수 있도록 변경해야 할 사항이 있습니까?

[쿼리 1]

select a1.*
from people a1
where a1.id like '119%' 
and rownum < 5

계획 설명
ALL_ROWS 문 선택
비용:67바이트:2,592 카디널리티:4
2 카운트 스톱키
1 테이블 액세스 전체 테이블 명
비용:67바이트:3,240 카디널리티:5

[질의 2]

select a1.*
from people a1, people a2
where a1.id = a2.id
and a2.id like '119%' 
and rownum < 5

계획 설명
ALL_ROWS 문 선택
비용:11바이트:2,620 카디널리티:4
5 카운트 스톱키
4 인덱스 ROWID 테이블 사용자별 테이블 액세스
비용:3바이트:648 카디널리티:1
3개의 중첩 루프
비용:11바이트:2,620 카디널리티:4
1 INDEX FAST FULL SCAN INDEX people_IDX3
비용:2바이트:54,796 카디널리티:7,828
2 INDEX RANGE SCAN INDEX people_IDX3
비용:2 카디널리티:1

[질의 3]

select a1.*
from people a1
where a1.code like '119%' 
and rownum < 5

계획 설명
ALL_ROWS 문 선택
비용:6바이트:1,296 카디널리티:2
3 카운트 스톱키
2 인덱스 ROWID 테이블 사용자별 테이블 액세스
비용:6바이트:1,296 카디널리티:2
1 INDEX RANGE SCAN INDEX people_IDX4
비용:3 카디널리티:2

도움이 되었습니까?

해결책

패턴 매칭 조건처럼 캐릭터 유형을 왼쪽 및 오른쪽에 피연산자로 볼 수 있습니다. 숫자가 발생하면 암시 적으로 Char로 변환합니다. 쿼리 1은 기본적으로 조용히 다시 작성됩니다.

SELECT a1.*
  FROM people a1
 WHERE TO_CHAR(a1.id) LIKE '119%'
   AND ROWNUM < 5

그것은 당신의 경우에 발생하며, 그것은 두 가지 이유가 나쁘다.

  1. 변환은 모든 행에 대해 실행되며 느리게 변환됩니다.
  2. Predicate의 함수 (암시 적으로)로 인해 Oracle은 인덱스를 사용할 수 없습니다. A1.ID 열.

주변을 둘러 보려면 다음 중 하나를 수행해야합니다.

  1. a 기능 기반 색인 ~에 A1.ID 열:

    CREATE INDEX people_idx5 ON people (TO_CHAR(id));

  2. ID 열의 첫 3 자에서 레코드를 일치시켜야하는 경우이 3 자만 포함하는 다른 유형 번호 열을 작성하고 평야를 사용하십시오. = 그것에 운영자.

  3. a 분리된ID_CHAR 유형의 VARCHAR2 그리고 그것을 채우십시오 TO_CHAR(id). 그것을 색인하고 대신 사용하십시오 ID 당신의 WHERE 상태.

    물론 기존 ID 열을 기반으로 추가 열을 만들려면 2 개의 동기화를 유지해야합니다. 단일 업데이트로 또는 업데이트 트리거로 수행하거나 해당 열에 해당 열을 추가 할 수 있습니다. 코드에 문을 삽입하고 업데이트하십시오.

다른 팁

LIKE는 문자열 함수이므로 숫자 인덱스를 쉽게 사용할 수 없습니다.숫자 인덱스에는 119,120,130,..,1191,1192,1193...,11921,11922...가 있습니다.등.즉, '119'로 시작하는 모든 행은 같은 위치에 있지 않으므로 전체 인덱스를 읽어야 합니다(따라서 FAST FULL SCAN).문자 기반 인덱스에서는 함께 표시되므로(예: '119','1191','11911','120',...) 더 나은 RANGE SCAN을 사용할 수 있습니다.

특정 범위(예: 119000~119999)에서 ID 값을 찾는 경우 해당 값을 조건자(119000~119999 사이의 ID)로 지정하세요.

Optimizer는 테이블 스캔을 수행하는 것이 더 빠르다고 결정했으며, 아마도 실제 레코드 수가 적기 때문일 수 있습니다.

또한, 당신은 비 홍보 일치가 항상 정확한 것보다 더 나쁘다는 것을 알아야합니다. "a1.id = '123456'"인 경우 대부분 인덱스를 사용할 것입니다. 그러나 다시 인덱스조차도 두 개의 읽기 (먼저 인덱스에서 레코드를 찾은 다음 테이블에서 블록을 읽습니다)와 테이블 스캔을 결정할 수있는 매우 작은 테이블의 경우 두 번의 읽기를 취합니다.

쿼리 중 하나에 힌트를 배치하여 원하는 색인을 사용하도록 강제로 계획 한 다음 계획을 확인하십시오. (기울어 지거나 기타로 인해) 최적화가 될 수 있습니다. 하다 인덱스를 고려하지만 인식 된 비용으로 인해 사용을 결정합니다.

그만큼 LIKE 키워드는 SQL에 정규 표현식 일치를하고 있다고 알려줍니다. 쿼리가 간단하게 표현 될 수 있는지 확인하기 위해 사용 가능한 문자열 함수를 확인할 때까지 SQL 또는 프로그래밍 라이브러리에서 정규식을 사용해서는 안됩니다. 이 경우 코드의 처음 3 자로 구성된 하위 문자 만 비교하여이를 동등한 조건으로 변경할 수 있습니다. 오라클에서는 다음과 같습니다.

SELECT *
FROM people
WHERE SUBSTR(code,1,3) = '119'
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top