2009-07-23 2 views
3

필자는 문제를 일으키기 위해 SQL 튜닝에 대해 충분히 알고 있습니다. 오늘 나는 질의에 대한 EXPLAIN 계획을 세우고 있었고 아마 그것이해야한다고 생각할 때 인덱스를 사용하지 않는 것으로 나타났습니다. 글쎄, 난 내가이 즉시 반환 확실히 생각테이블의 고유 한 필드에 대한 인덱스는 select count (*)가 즉시 발생하도록 허용합니까? 왜 안되면?

select count(*) from table_name 

에 EXPLAIN했다 때까지, 간단하고 단순한 (내 마음에 더 색인) 쿼리에 EXPLAIN하고 그 보관 인덱스의 사용을 보여줄 것입니다 설명 이 테이블에는 고유 한 row_id 열의 인덱스를 비롯하여 많은 인덱스가 있으므로 그러나 Explain 계획은 FULL 테이블 스캔을 보여 주 었으며 완료하는 데 몇 초가 걸렸습니다. (이 표에는 3 백만 행이 있습니다).

오라클이 전체 테이블 스캔을 수행하여이 테이블의 행을 계산하는 이유는 무엇입니까? 나는 오라클이 이미 고유 한 필드를 인덱싱하고 있으며 해당 테이블의 모든 삽입 및 업데이트를 추적해야하므로 어딘가에 행 수가 캐싱 될 것이라고 생각하고 싶습니다. 그렇지 않은 경우에도 전체 테이블을 스캔하는 것보다 전체 인덱스를 스캔하는 것이 더 빠르지 않습니까?

두 가지 이론이 있습니다. 이론 1은 인덱스가 어떻게 잘못 작동하는지 상상하고 있습니다. 이론 2는 오라클 설정의 일부 설정이나 매개 변수가 오라클의 쿼리 최적화 기능을 망치고 있다는 것입니다 (우리는 oracle 9i를 사용하고 있습니다). 누구나 나를 계몽시킬 수 있습니까?

+0

거래에 대한 좋은 지적은 내 머리 속에 떠오르는 것보다 더 복잡해졌습니다. –

답변

4

OracleCOUNT(*)을 캐시하지 않습니다. MyISAM이 transactionless이고 같은 COUNT(*)는 누구나 볼 수 있기 때문에 MyISAM

MySQL는 (이 감당할 수) 않습니다.

Oracle은 트랜잭션이며, 다른 트랜잭션에서 삭제 된 행은 거래에서 계속 볼 수 있습니다.

Oracle은 스캔해야하며, 삭제 된 것을 확인하려면 UNDO을 방문하십시오. 거래의 관점에서 볼 때 여전히 올바른지 확인하고 개수에 추가하십시오.

UNIQUE 값을 인덱싱하는 것은 논리적으로 만 UNIQUE이 아닌 값을 인덱싱하는 것과 다릅니다.

실제로 고유하지 않은 인덱스가 정의 된 열에 대해 UNIQUE 제약 조건을 만들 수 있으며 인덱스를 사용하여 제약 조건을 적용 할 수 있습니다.

열이 NULL이 아닌 것으로 표시된 경우 COUNT에이 열의 INDEX FAST FULL SCAN을 사용할 수 있습니다.

색인 순서가 중요하지 않은 경우 사용되는 특수 액세스 방법입니다. B-Tree을 트래버스하지 않고 순차적으로 페이지를 읽습니다.

인덱스가 테이블 자체보다 페이지가 있기 때문에, COUNT가 빠를 INDEX_FFSFULL

+0

그것은 문제가 아닌 무효였다. 열이 널이 아닌 것으로 설정되면 빠른 전체 스캔이 진행 중입니다. –

+0

@Peter : 쿼리가 하나의 열 (SELECT' 절, WHERE' 절 및'ORDER BY' 절)에 관련된 경우,'INDEX_FFS' 대신'FULL' 스캔이 종을 울려 야합니다. – Quassnoi

0

이 '거래'이유에 조금 확장보다 될 수 있습니다. 데이터베이스가 트랜잭션을 지원할 때, 언제든지 "상태"가 다른 상태의 레코드가있을 수 있습니다. 트랜잭션이 실패하면 상태가 롤백됩니다.

전체 테이블 검색은 각 레코드의 현재 "버전"이 해당 시점에 액세스 될 수 있도록 수행됩니다.

MySQL MyISAM은 트랜잭션에 필요한 레코드 잠금 대신 테이블 잠금을 사용하고 레코드 카운트를 캐시하므로이 문제가 발생하지 않습니다. 항상 즉시 반환됩니다. MySQL에서 InnoDB는 오라클과 동일하게 작동하지만 반환하고 "예상"합니다.

기본 키의 고유 값을 계산하면 더 빠른 쿼리를 얻을 수 있으며 인덱스 만 액세스 할 수 있습니다.

2

오라클이 인덱스 (특히 INDEX FAST FULL SCAN)를 사용하여 이러한 쿼리를 충족시킬 수는 있습니다. 그 경로를 선택할 수있는 최적화 위해서는

, 적어도 두 가지 사실이 있습니다

  1. 오라클이 테이블의 모든 행이 인덱스에 표시되는 것을 확신하는 - 즉, 기본적으로 인덱스에 누락 된 NULL 항목이 없습니다. 기본 키를 가지고 있다면 이것이 보장되어야합니다.
  2. 오라클은 인덱스 스캔 비용을 테이블 스캔 비용보다 낮게 계산해야합니다. 인덱스 스캔이 항상 저렴하다고 가정하는 것은 필연적이라고 생각하지 않습니다.

아마도 통계를 수집하면 동작이 변경됩니다.

+0

통계는 지난 주에 나온 것이므로 테이블은 오랫동안 3 백만 행에 있었으므로 삭제할 수 있다고 생각합니다. 내가 row_id 컬럼을 null로 표시하는 것을 실험 할 것입니다. - 그냥 체크해 보았습니다. row_id가 기본 키처럼 보이고 사용되었지만 공급 업체가 "not null"을 지정하지 않았습니다! –

+1

가정 된 기본 키 열을 "not null"로 변경 한 후에 Oracle은 빠른 전체 검색을 수행합니다! –