2009-04-07 2 views
18

SQL 코드에서 "ORDER BY"구문을 사용하여 성능 문제가 발생했습니다.ORDER BY를 사용할 때 MySQL이 인덱스를 사용하지 않습니다 ("filesort 사용").

SQL에서 ORDER BY 문을 사용하지 않는 한 모든 것이 좋습니다. 그러나 일단 ORDER BY : SQL 코드를 도입하면 올바른 인덱싱의 부재로 인해 모든 것이 느려집니다. 하나는이 문제를 해결하는 것이 사소한 것이라고 생각하지만, 포럼 토론 등으로 판단하는 것은이 질문에 대한 명확하고 간결한 대답을 아직 보지 못한 다소 일반적인 문제인 것으로 보입니다. 내가 값을 정렬하는 동안 값 1 - 범위의 테이블을 쿼리 할 때 사용할 인덱스를 만들려면 어떻게해야 주어진 다음의 표 ...

 
CREATE TABLE values_table (
    id int(11) NOT NULL auto_increment, 
    ... 
    value1 int(10) unsigned NOT NULL default '0', 
    value2 int(11) NOT NULL default '0', 
    PRIMARY KEY (id), 
    KEY value1 (value1), 
    KEY value2 (value2), 
) ENGINE=MyISAM AUTO_INCREMENT=2364641 DEFAULT CHARSET=utf8; 

... :

질문 값 2?

현재 ORDER BY 절을 사용하지 않으면 가져 오기가 정상입니다.

는 EXPLAIN 다음 쿼리 출력을 참조하십시오

 
OK, when NOT using ORDER BY: 

EXPLAIN select ... from values_table this_ where this_.value1 between 12345678 and 12349999 limit 10; 

+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ 
| 1 | SIMPLE  | this_ | range | value1  | value1 | 4  | NULL | 3303 | Using where | 
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ 
 
However, when using ORDER BY I get "Using filesort": 

EXPLAIN select ... from values_table this_ where this_.value1 between 12345678 and 12349999 order by this_.value2 asc limit 10; 

+----+-------------+-------+-------+---------------+----------+---------+------+------+-----------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra      | 
+----+-------------+-------+-------+---------------+----------+---------+------+------+-----------------------------+ 
| 1 | SIMPLE  | this_ | range | value1  | value1 | 4  | NULL | 3303 | Using where; Using filesort | 
+----+-------------+-------+-------+---------------+----------+---------+------+------+-----------------------------+ 

테이블 내용에 대한 몇 가지 추가 정보 :

 
SELECT MIN(value1), MAX(value1) FROM values_table; 
+---------------+---------------+ 
| MIN(value1) | MAX(value2) | 
+---------------+---------------+ 
|    0 | 4294967295 | 
+---------------+---------------+ 

... 

SELECT MIN(value2), MAX(value2) FROM values_table; 
+---------------+---------------+ 
| MIN(value2) | MAX(value2) | 
+---------------+---------------+ 
|    1 |  953359 | 
+---------------+---------------+ 

어떤 추가 정보가 질문에 대답 할 필요가 있으면 알려 주시기 바랍니다 .

미리 감사드립니다.

업데이트 # 1 : 새로운 복합 인덱스를 추가 (ALTER 테이블 INDEX (값 1, 값을 ADD values_table)는) 문제가 해결되지 않습니다. 이러한 인덱스를 추가 한 후에도 "Using filesort"가 표시됩니다.

업데이트 # 2 : 제약 조건 내 질문에 언급하지 않았다 차라리 사용하는 SQL 쿼리를 변경하는 대신 (말 등, 인덱스를 추가) 테이블의 구조를 변경 것이다. SQL 질의는 Hibernate를 사용하여 자동으로 생성되기 때문에, 그것들을 다소 고칠 수도있다.

+0

귀하의 업데이트에서 value1, value2를 의미한다고 가정합니다. 그렇습니까? – paxdiablo

+0

@ Quassnoi가 value1 범위에 대해 설명했기 때문에 어쨌든 작동하지 않습니다. 그것은 가치 1의 단일 가치를 위해 일했을 것입니다. 그러나 나는 그 질문을 충분히 읽지 않았습니다. 행운을 빌어 요. – paxdiablo

+0

쿼리에서 필드를 직접 사용하거나 함수를 사용하고 있습니까? 타임 스탬프 필드 및 WEEK (타임 스탬프)와 같습니다. –

답변

19

RANGE 필터링 조건을 사용하면이 경우 색인을 사용할 수 없습니다.

당신은 같은 것을 사용하려는 경우 : 다음 (VALUE1, VALUE2)에 복합 인덱스를 생성,

SELECT * 
FROM values_table this_ 
WHERE this_.value1 = @value 
ORDER BY 
     value2 
LIMIT 10 

는 필터링 및 주문 모두에 사용됩니다.

하지만 원거리 조건을 사용하기 때문에 어쨌든 주문을 수행해야합니다.

귀하의 종합 지수는 다음과 같이됩니다 : 당신이 value112을 선택하면

 
value1 value2 
----- ------ 
1  10 
1  20 
1  30 
1  40 
1  50 
1  60 
2  10 
2  20 
2  30 
3  10 
3  20 
3  30 
3  40 

, 그리고, 당신은 여전히 ​​value2의 전체 소트 세트를 얻을 수 없습니다.

CREATE INDEX ix_table_value2_value1 ON mytable (value2, value1) 

/* Note the order, it's important */  

SELECT * 
FROM (
     SELECT DISTINCT value2 
     FROM mytable 
     ORDER BY 
       value2 
     ) q, 
     mytable m 
WHERE m.value2 >= q.value2 
     AND m.value2 <= q.value2 
     AND m.value1 BETWEEN 13123123 AND 123123123 

이것은 SKIP SCAN 액세스 방법이라고 : value2에 색인이 매우 선택적이 아닌 경우

, 당신은 시도 할 수 있었다 (.. 즉 테이블에 DISTINCT value2 많은 것이 아니다). MySQL은 직접 지원하지 않지만 이와 같이 에뮬레이션 할 수 있습니다.

이 경우에는 RANGE 액세스가 사용되지만 DISTINCT value2 행이 약 1% 개 미만인 경우 성능상의 이점을 얻을 수 없습니다. 의

주 사용 :

m.value2 >= q.value2 
AND m.value2 <= q.value2 

대신이 각 루프에 확인 MySQL 수행 RANGE하게

m.value2 = q.value2 

의.

+0

범위 문제를 해결하기 위해 +1 :-) – paxdiablo

+0

종합적인 답변을 주셔서 감사합니다. 내가 사용하는 SQL 쿼리 (Hibernate에 의해 자동 생성 된)를 변경할 수 없다고 가정하면, 더 좋은 인덱싱을 추가함으로써 이것을 해결하는 것이 불가능하다고 생각합니까? – knorv

+0

또 다른 질문 : 범위 쿼리가 문제라면 ORDER BY를 사용하지 않을 때 어떻게 모든 것이 정상적으로 보일까요? 미안하다면 나는이 세부 사항을 놓쳤다. – knorv

0

나는 개의 독립적 인 키를 가지고 있습니다. 하나는 value1이고 다른 하나는 value2입니다.

그래서 value1 키를 사용하여 검색 할 때 레코드는 반드시 value2 순서로 반환되지 않으므로 정렬해야합니다. "where value1"절을 만족하는 레코드 만 정렬하기 때문에 여전히 전체 테이블 스캔보다 좋습니다.

나는 이것이 (MySQL에서 가능하다면), (value1, value2)의 합성 키가 이것을 해결할 것이라고 생각한다.

보십시오

CREATE TABLE values_table (
    id int(11) NOT NULL auto_increment, 
    ... 
    value1 int(10) unsigned NOT NULL default '0', 
    value2 int(11) NOT NULL default '0', 
    PRIMARY KEY (id), 
    KEY value1 (value1), 
    KEY value1and2 (value1,value2), 
) ENGINE=MyISAM AUTO_INCREMENT=2364641 DEFAULT CHARSET=utf8; 

(또는 등가 ALTER TABLE), 즉 복합 키 MySQL은 올바른 가정 구문이다.

DB 엔진이 행을 검색하기 위해 value1and2 키를 선택하게하고 그 값이 이미 value2-within-value로 정렬 될 것이라고 알고있는 모든 데이터베이스에서 (그리고 MySQL이 그 중 하나가 아닌 것을 인정해야합니다) value1 순서이므로 파일 정렬이 필요하지 않습니다.

필요한 경우 value2 키를 계속 보관할 수 있습니다.

+0

안녕하세요, 빠른 답장을 보내 주셔서 감사합니다. 제안한 솔루션을 시도했지만 불행히도 문제가 해결되지 않았습니다. 내 질문에 대한 설명을 추가했습니다. – knorv

+0

@Quassnoi는 MySQL에 대한 지식이 더 많은 것으로 보이므로 문제를 해결할 것입니다. 원거리 값 1에 정렬이 필요한 이유에 대한 그의 설명은 DB2에서 비슷한 probs를 가졌을 것이라는 의문을 제기하지 않았습니다. 커뮤니티 위키로 언급하여 다른 누구도 똑같은 실수를 저 지르지는 않습니다. – paxdiablo

+0

커뮤니티 위키를 표시하지 못하게하는 버그가 있습니다. – paxdiablo

관련 문제