2013-12-16 2 views
1

가입 :MySQL의 이상한 성능 이상 나는 다음과 같은 간단한 왼쪽 쿼리에 가입 한

SELECT SQL_NO_CACHE * FROM helyek h 
    LEFT JOIN eladok e ON e.elado_id = h.elado_id 
    LEFT JOIN eladok_rel_szakmak ersz ON ersz.elado_id = e.elado_id 
    LEFT JOIN szakmak sz ON sz.szakma_id = ersz.szakma_id 
WHERE h.hely_nev = 'xy' 
    OR h.hely_telepules = 'xy' 

모든 _id와 h.hely_nev이 h.hely_telepules 인덱싱하며 0.0008 초에서 실행됩니다.

하지만 하나 이상의 where 절을 추가하면 (OR sz.szakma_id = 1) 속도가 0.7 초로 떨어집니다! 이것은 정말로 느립니다. helyek, eladok, eladok_rel_szakmak에

SELECT SQL_NO_CACHE * FROM helyek h 
    LEFT JOIN eladok e ON e.elado_id = h.elado_id 
    LEFT JOIN eladok_rel_szakmak ersz ON ersz.elado_id = e.elado_id 
    LEFT JOIN szakmak sz ON sz.szakma_id = ersz.szakma_id 
WHERE h.hely_nev = 'xy' 
    OR h.hely_telepules = 'xy' 
    OR sz.szakma_id = 1 

50K szakmak 행에서 30 행. 나는 모든 분야에서 필요한 분야가 있기 때문에 모든 테이블에 합류해야한다.

질문은 어떻게하면 더 나은 수행을 위해 두 번째 쿼리를 최적화 할 수 있습니까?

이 빠른 쿼리입니다가 :

+----+-------------+-------+-------------+------------------------------+------------------------------+---------+----------------+------+--------------------------------------------------------+ 
| id | select_type | table | type  |  possible_keys   |    key    | key_len |  ref  | rows |       Extra       | 
+----+-------------+-------+-------------+------------------------------+------------------------------+---------+----------------+------+--------------------------------------------------------+ 
| 1 | SIMPLE  | h  | index_merge | idxhelynev,idxhely_telepules | idxhelynev,idxhely_telepules | 482,482 | NULL   | 2 | Using union(idxhelynev,idxhely_telepules); Using where | 
| 1 | SIMPLE  | e  | eq_ref  | PRIMARY      | PRIMARY      | 4  | h.elado_id  | 1 |              | 
| 1 | SIMPLE  | ersz | ref   | elado_id      | elado_id      | 4  | e.elado_id  | 1 |              | 
| 1 | SIMPLE  | sz | eq_ref  | PRIMARY      | PRIMARY      | 4  | ersz.szakma_id | 1 |              | 
+----+-------------+-------+-------------+------------------------------+------------------------------+---------+----------------+------+--------------------------------------------------------+  

이것은 느린 : 여기

는이 설명되어 내가 두 번째 쿼리는 어떤 키를 사용하지 못할 참조

+----+-------------+-------+--------+------------------------------+----------+---------+----------------+-------------+-------------+ 
| id | select_type | table | type |  possible_keys   | key | key_len |  ref  | rows  | Extra | 
+----+-------------+-------+--------+------------------------------+----------+---------+----------------+-------------+-------------+ 
| 1 | SIMPLE  | h  | ALL | idxhelynev,idxhely_telepules | NULL  | NULL | NULL   | 54326  |    | 
| 1 | SIMPLE  | e  | eq_ref | PRIMARY      | PRIMARY | 4  | h.elado_id  |   1 |    | 
| 1 | SIMPLE  | ersz | ref | elado_id      | elado_id | 4  | e.elado_id  |   1 |    | 
| 1 | SIMPLE  | sz | eq_ref | PRIMARY      | PRIMARY | 4  | ersz.szakma_id |   1 | Using where | 
+----+-------------+-------+--------+------------------------------+----------+---------+----------------+-------------+-------------+ 

,하지만 난 왜 그런지 모르겠다. (sz.szakma_id 필드에 색인이있다.)

편집 : 나는 잊고 : 나는 둘 이상의 조항 그룹을 사용해야합니다. 이와 같이 :

(h.hely_nev = 'x' OR h.hely_telepules = 'x' OR sz.szakma_id = x) 
AND 
(h.hely_nev = 'y' OR h.hely_telepules = 'y' OR sz.szakma_id = y) 
AND 
(h.hely_nev = 'z' OR h.hely_telepules = 'z' OR sz.szakma_id = z) 

그 이유는 두 가지 별도의 쿼리를 사용합니다. 목표는 사용자가 검색 양식에 입력하는 모든 단어에 대해 h.hely_nev, h.hely_telepules, sz.szakma_id 필드를 검색하는 것입니다. 예를 들어 사용자가 "x y z"를 입력하면 h.hely_nev가 x 또는 y 또는 z와 같고 h.hely_telepules이 x 또는 y 또는 z와 같은 모든 레코드를 선택해야합니다.

+0

사용이 쿼리 대신 1 - 너무 많이 또는의 당신과 유감 감사 – matino

답변

4

첫 번째 경우에 쿼리 최적화 프로그램은 helyek에있는 인덱스를 사용하여 후보 행을 두 개만 결정할 수 있기 때문입니다.

szakmak에 OR 조건을 추가하면 잠재적 결과 집합을 좁히기 위해 helvek에 인덱스를 사용할 수 없습니다.당신은 아마 최고의 두 개의 별도의 쿼리 조건 중 하나의 결과를 UNION 할 제공 될 것입니다 : 조건

WHERE h.hely_nev = 'xy' 
OR h.hely_telepules = 'xy' 

하고 다른

WHERE sz.szakma_id = 1 

그래서 뭔가 같은 :

SELECT SQL_NO_CACHE * FROM helyek h 
    LEFT JOIN eladok e ON e.elado_id = h.elado_id 
    LEFT JOIN eladok_rel_szakmak ersz ON ersz.elado_id = e.elado_id 
    LEFT JOIN szakmak sz ON sz.szakma_id = ersz.szakma_id 
WHERE h.hely_nev = 'xy' 
    OR h.hely_telepules = 'xy' 
UNION DISTINCT 
SELECT SQL_NO_CACHE * FROM helyek h 
    LEFT JOIN eladok e ON e.elado_id = h.elado_id 
    LEFT JOIN eladok_rel_szakmak ersz ON ersz.elado_id = e.elado_id 
    LEFT JOIN szakmak sz ON sz.szakma_id = ersz.szakma_id 
WHERE sz.szakma_id = 1 

szakmak 테이블의 카디널리티가 더 적고 (주어진 필터 조건에 대해 행이 더 많음)이 아닌 경우 일련의 올바른 조인을 사용할 수도 있습니다

그래서 당신은 다음과 같이 쿼리를 주위 플립 :

SELECT SQL_NO_CACHE * 
FROM 
    szakmak sz 
    RIGHT JOIN eladok_rel_szakmak ersz ON sz.szakma_id = ersz.szakma_id 
    RIGHT JOIN eladok e ON ersz.elado_id = e.elado_id 
    RIGHT JOIN helyek h ON e.elado_id = h.elado_id 
WHERE h.hely_nev = 'xy' 
    OR h.hely_telepules = 'xy' 
    OR sz.szakma_id = 1 

이 테이블 종속성 순서를 변경합니다. 나는 당신에게 가장 잘 어울리는 것이 확실하지 않습니다. 좌/우 여기에 최적화 가입에

는 MySQL의 문서에서 더 많은 정보를 참조하십시오 :

http://dev.mysql.com/doc/refman/5.6/en/left-join-optimization.html

+0

성능을 죽일 것이다 :(내가 잊었 언급 : 하나 이상의 조항 그룹을 사용해야합니다. (질문 편집) – user974250

+0

@ user974250 결국 아주 추악한 검색어가됩니다. 내게는 솔루션을위한 스키마를 바라는 것이 좋습니다. 이러한 복잡한 방식으로 레코드를 필터, 이러한 행을 관련시킬 수있는 더 좋은 방법이 있는지 궁금합니다. 귀하의 예제에서 경우 wher 확인하는 찾고 있습니다 e 행은 세 개의 필드에서 세 가지 값 중 하나를 가져야하지만 각 레코드는 각 위치에서 고유 한 값을 가져야합니다. (종류는 기안자 퍼즐과 같습니다). 이는 AND로 이러한 필터 조건을 결합하기 때문입니다. –

+0

네 맞습니다. 그래서 내가 AND와 조건에 합류해야하는 이유이며 그 이유는 내가 조건을 구분할 수없는 이유입니다. – user974250