2011-03-10 2 views
2

가는 표 스캔.SQL 쿼리 내가 두 개의 테이블이 아닌 인덱스 기반의 스캔 전체 테이블에 대한 검사

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2290496975 
---------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
---------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  | 3737 | 97162 | 85 (3)| 00:00:02 | 
|* 1 | FILTER   |  |  |  |   |   | 
| 2 | TABLE ACCESS FULL| BIG | 74718 | 1897K| 85 (3)| 00:00:02 | 
|* 3 | TABLE ACCESS FULL| SMALL |  1 |  4 |  3 (0)| 00:00:01 | 
---------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

1 - filter("ID"=45 OR EXISTS (SELECT /*+ */ 0 FROM "SMALL" "SMALL" 

      WHERE "ID"=:B1)) 

3 - filter("ID"=:B1) 

언제든지 색인 스캔을 위해 쿼리를 다시 작성할 수있는 방법이 있습니까? 이 같은

+1

는 오타인가요 - 그것은 누구의 데이터 형 컬럼에 LIKE 사용에 대한 오류가있을 거라고 생각 관련된 문자열 (VARCHAR2 등) –

+0

아니다 이드가 45 살부터 시작했으면 좋겠어? 45, 45029, 451 같은 거요? –

+0

예 jon 당신이 맞습니다 – Ajitesh

답변

-1

뭔가 작동 할 수 있습니다 :

select * 
    from big_table big 
where id like '45%' 
    or exists (select id from small_table where id = big.id); 
+0

안녕 Sunil 나는 그것을 시도했지만 같은 결과가 실행 계획 | 이드 | 운영 | 이름 | 행 | 바이트 | 비용 (% CPU) | 시간 | ------------------------------------------------- --------------------------- | 0 | SELECT 문 | | 3737 | 97162 | 85 (3) | 00:00:02 | | * 1 | 필터 | | | | | | | 2 | 테이블 액세스 FULL | 빅 | 74718 | 1897K | 85 (3) | 00:00:02 | | * 3 | 테이블 액세스 FULL | 작은 | 1 | 4 | 3 (0) | 00:00:01 | – Ajitesh

3

아니, 아니없고.

색인을 사용하고 싶지는 않습니다. 운 좋게도 오라클은 그보다 더 똑똑합니다.

ID는 숫자입니다. ID 값이 45,4504514524501450044500003 등일 수 있지만 인덱스에는 이러한 값이 어디서나 흩어져 있습니다. ID BETWEEN 450 AND 459와 같은 상태로 갔다면 색인을 사용하는 것이 좋습니다.

인덱스를 사용하려면 위에서 아래로 모든 방법을 스캔해야합니다 (각 ID를 LIKE 비교를 수행하는 문자로 변환). 그런 다음 일치하는 항목이 있으면 NAME 열을 가져와야합니다.

인덱스와 테이블 사이를왔다 갔다하기보다는 테이블을 스캔하는 것이 더 쉽고 빠르다는 결론을 얻었습니다 (75,000 행은 그다지 크지 않습니다).

+2

Spot on. 그렇게하는 방법은 ID를 문자열로 변환하는 함수 기반 인덱스가 될 것입니다. 그러면 LIKE는 더 나은 용어를 원한다면 "올바르게"작동합니다. – lll

1

다른 것은 맞습니다. 그런 숫자 열을 사용하면 안됩니다.

그러나 실제로이 경우 성능 문제를 일으키는 것은 OR <subquery> 구조입니다. 나는 그것이 버전 11에서 다르지만 버전 10gr2까지인지 아닌지를 알지 못한다. 기본적으로 상관 하위 쿼리가있는 중첩 루프 인 필터 연산이 발생한다. 귀하의 경우, 숫자 열을 varchar로 사용하면 전체 테이블이 검색됩니다.

당신은 다음과 같이 쿼리를 다시 작성할 수 있습니다 : 테스트 케이스

select * 
    from big 
where id like '45%' 
union all 
select * 
    from big 
    join small using(id) 
where id not like '45%'; 

을, 나는 행 큰에서 174,000 행의 수와 9 작은 끝낼. 쿼리를 실행하는 데 1211399 개의 일치하는 가져 오기가 소요됩니다. 내 쿼리를 0,7 초 실행하고 542 일치를 사용합니다.

(가) 내 쿼리에 대한 계획을 설명은 다음과 같습니다

-------------------------------------------------------------------- 
| Id | Operation      | Name | Rows | Cost (%CPU)| 
--------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |  | 8604 | 154 (6)| 
| 1 | UNION-ALL     |  |  |   | 
|* 2 | TABLE ACCESS FULL   | BIG | 8603 | 151 (4)| 
| 3 | NESTED LOOPS    |  |  1 |  3 (0)| 
|* 4 | TABLE ACCESS FULL   | SMALL |  1 |  3 (0)| 
| 5 | TABLE ACCESS BY INDEX ROWID| BIG |  1 |  0 (0)| 
|* 6 |  INDEX UNIQUE SCAN   | BIG_PK |  1 |  0 (0)| 
--------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - filter(TO_CHAR("ID") LIKE '45%') 
    4 - filter(TO_CHAR("SMALL"."ID") NOT LIKE '45%') 
    6 - access("BIG"."ID"="SMALL"."ID") 


Statistics 
---------------------------------------------------------- 
      1 recursive calls 
      0 db block gets 
     542 consistent gets 
      0 physical reads 
      0 redo size 
     33476 bytes sent via SQL*Net to client 
     753 bytes received via SQL*Net from client 
     76 SQL*Net roundtrips to/from client 
      0 sorts (memory) 
      0 sorts (disk) 
     1120 rows processed 
관련 문제