2010-04-15 1 views
3

쿼리 성능 문제를 해결하는 중입니다.키가 존재할 때 InnoDB가 테이블 스캔을하고, 70 배 더 많은 행을 검사하도록 선택하는 이유는 무엇입니까?

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:16'; 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+ 
| id | select_type | table    | type | possible_keys | key   | key_len | ref | rows | Extra  | 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+ 
| 1 | SIMPLE  | table1    | range | tdcol   | tdcol  | 8  | NULL | 5437848 | Using where | 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+ 
1 row in set (0.00 sec) 

의미가 인덱스 이름 tdcol (KEY tdcol (tdcol))을 사용, 약 5M 행이 쿼리에서 선택해야하기 때문에, 다음은 설명에서 예상되는 쿼리 계획이다. 내가 데이터를 하나 더 분 동안 질의 경우

그러나, 우리는이 쿼리 계획을 얻을 :

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:17'; 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+ 
| id | select_type | table    | type | possible_keys | key | key_len | ref | rows  | Extra  | 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+ 
| 1 | SIMPLE  | table1    | ALL | tdcol   | NULL | NULL | NULL | 381601300 | Using where | 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+ 
1 row in set (0.00 sec) 

최적화는 검색이 잘 될 것이라고 생각하지만, 너무, 70 배 이상 더 많은 행이 검사의 나는 테이블 스캔이 더 좋다고 믿기가 힘듭니다.

또한 'USE KEY tdcol'구문은 쿼리 계획을 변경하지 않습니다.

도움을 주셔서 감사 드리며, 더 많은 정보/질문에 답해 드리겠습니다.

+1

첫 번째 쿼리의 첫 번째 날짜에 여분의 콜론이 잘못된 복사/붙여 넣기가 있습니까? –

+0

은 날짜 키 – DRapp

+0

예 great_llama에서 간단해야하며, 이는 잘못된 복사 및 붙여 넣기입니다. 편집 됨. – andysk

답변

3

3 억 5 천만 개의 행 (순차적 디스크 읽기)을 읽는 것보다 500 만 개의 인덱스 프로브가 더 비쌀 수 있습니다 (많은 디스크 읽기, 잠재적으로 더 복잡한 동기화).

타임 스탬프의 순서가 테이블 삽입 순서와 대략 일치하기 때문에이 경우는 예외 일 수 있습니다. 하지만 tdcol의 인덱스가 "클러스터 된"인덱스가 아니면 (즉, 기본 테이블의 순서가 tdcol의 순서와 일치 함을 의미 함) 옵티마이 저가이를 알고있는 것 같지 않습니다.

해당 순서 상관 정보가 없으면 원하는 5 백만 행이 약 3 억 5 천만 행에 균등하게 분산되어 있다고 가정하면 색인 방법은 대부분 또는 거의 모두를 읽는 것으로 간주됩니다. 어쨌든 기본 행에있는 페이지 (이 경우 스캔은 인덱스 방식보다 훨씬 저렴하고 무작위 읽기보다는 순차적 읽기가 적음).

+0

덕, 고맙습니다. 귀하의 가정은 사실입니다 -이 datetime 열'tdcol'은 클러스터 된 색인, 단순한 일반 색인에 없습니다 - 불행히도 값이 고유하지 않기 때문에 초당 여러 개의 레코드가 있습니다. 예, 인덱스 순서는 디스크의 데이터 삽입/레이아웃 순서와 밀접하게 일치하지만 옵티마이 저는이를 알 수 없습니다. 그리고 페이지 측면에서 흥미로운 점을 만들 수 있습니다. 인덱스 된 행이 무작위로 배포되고 페이지 당 적어도 70 개의 행이 있으면 그만 스캔을 정당화 할 수 있습니다. – andysk

+0

MySQL에서는 클러스터 된 인덱스가 고유해야합니다. 왜? –

+0

그것이 내가 읽는 방법입니다. http://dev.mysql.com/doc/refman/5.1/en/innodb-index-types.html 클러스터 된 인덱스가 고유해야하는 이유가 표시되지 않습니다. – andysk

0

MySQL의 쿼리 생성기는 인덱스 사용 방법을 결정할 때 단절이 있습니다. 올바르게 식별 했으므로, MySQL은 인덱스를 사용하는 것보다 테이블 스캔이 빠르다고 결정했으며, 그 결과로 결정을 내리지 않습니다. 아이러니 한 점은 키 범위가 테이블의 약 3 분의 1 이상과 일치 할 때가 맞을 수도 있다는 것입니다. 왜이 경우에?

답변이 없지만 의문의 여지가 있습니다. MySQL에 색인을 탐색 할 메모리가 충분하지 않습니다. 나는 서버 메모리 설정, 특히 Innodb 메모리 풀과 다른 주요 저장 영역 풀을 조사 할 것이다.

+0

감사 통계. 당신이 말하는 것은 말이되는데, 사실이 상자는 테이블 크기에 비해 메모리가 부족합니다. 그러나 흥미롭게도 버퍼 풀을 5.5GB의 메모리에서 27GB의 메모리로 재구성했으며 다른 변경 사항은 없었으며 쿼리 계획을 전혀 변경하지 않았습니다. – andysk

0

데이터 배포에는 어떤 것이 있습니까? 그것이 어디에 있는지보기 위해 min(), avg(), max()를 실행 해보십시오. 1 분이면 해당 범위에 포함 된 정보의 양이 달라질 수 있습니다.

InnoDB의 배경 설정 일 수도 있습니다. 페이지 크기와 같은 몇 가지 요소가 있으며, staticsan과 같은 메모리가 있습니다. 명시 적으로 B + Tree 인덱스를 정의하고자 할 수 있습니다.

+0

이것은 1 년 이상에 걸쳐 선택하려고하는 날짜/시간 필드입니다. 최근 일 평균 약 5 백만 기록. 꽤 균등하게 배포됩니다. 이 경우, 1 분은 1200 레코드이며, 이는 중요하지 않습니다. 내 설정이 중요하다는 데 동의했습니다. 설정이이 설정 (http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/)과 거의 일치하지만 페이지 크기를 확인해야합니다. 명시 적으로 B + Tree 인덱스를 정의 할 수 있습니다. – andysk

0

"그래서 테이블 스캔이 더 좋다고 믿기가 힘듭니다."

참. YOU 믿기 힘듭니다. 그러나 옵티마이 저는 그렇게하지 않는 것 같습니다.

귀하의 옵티마이 저가 "적절하다"대 귀하의 "적절한"발음을하지 않겠습니다. 그러나 옵티마이 저는이를 수행하는대로 수행하며, 모두 "지적"용량은 여전히 ​​제한적이라고 여겨 져야합니다.

즉, 데이터베이스 통계에 "1 초 이상"값과 동일한 MAX 값 (이 열)이 표시됩니까?

그렇다면 옵티마이 저는 모든 행이 상한선을 만족한다고 결론을 내릴 수 있으며 "오, 명확히 원 행이 있습니다. 상한선도 만족하지 않으므로 색인을 안전한면에 사용하겠습니다. "

+0

피드백에 감사드립니다. Erwin - 테이블 상태가 아니기 때문에 통계에서 MAX를 어떻게 볼 수 있습니까? – andysk