2017-03-28 16 views
2

를 검색합니다. 그것은 BY ORDER를 보인다 LIMIT는MySQL의 차이가 나는 쿼리가

비효율적 ORDER BY와 LIMIT없이하고 있습니다 : 적은 수에 스캔 중첩 된 쿼리를 생성

mysql> SELECT count(*) 
    FROM OTHERS_TINY_URL_TBL 
    WHERE LINK_TYPE = 'BITLY' 
     AND URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11' 
     AND MODIFIED_TM >= '2016-03-13 21:09:43' 
     AND MODIFIED_TM <= '2017-03-13 21:09:43' 
     AND POST_ID < 0\G; 
*************************** 1. row *************************** 
count(*): 85 
1 row in set (0.02 sec) 

ERROR: 
No query specified 

:

mysql> explain SELECT * 
    FROM OTHERS_TINY_URL_TBL 
    WHERE LINK_TYPE = 'BITLY' 
     AND URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11' 
     AND MODIFIED_TM >= '2016-03-13 21:09:43' 
     AND MODIFIED_TM <= '2017-03-13 21:09:43' 
     AND POST_ID < 0\G; 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: OTHERS_TINY_URL_TBL 
     type: range 
possible_keys: XIE1_OTHERS_TINY_URL_TBL,XIE2_OTHERS_TINY_URL_TBL,XIE5_OTHERS_TINY_URL_TBL 
      key: XIE2_OTHERS_TINY_URL_TBL 
     key_len: 9 
      ref: NULL 
     rows: 4950 
     Extra: Using index condition; Using where 
1 row in set (0.00 sec) 

ERROR: 
No query specified 

만 85 개 필터링 된 세트의 행 행의 :

mysql> explain SELECT * 
    FROM 
    (
     SELECT * 
      from OTHERS_TINY_URL_TBL 
      where URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11' 
       AND MODIFIED_TM >= '2016-03-13 21:09:43' 
       AND MODIFIED_TM <= '2017-03-13 21:09:43' 
       AND POST_ID < 0 
    ) inner_t 
    where true 
    ORDER BY MODIFIED_TM DESC 
    LIMIT 1000\G; 
*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: <derived2> 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 4950 
     Extra: Using filesort 
*************************** 2. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: OTHERS_TINY_URL_TBL 
     type: range 
possible_keys: XIE2_OTHERS_TINY_URL_TBL,XIE5_OTHERS_TINY_URL_TBL 
      key: XIE2_OTHERS_TINY_URL_TBL 
     key_len: 9 
      ref: NULL 
     rows: 4950 
     Extra: Using index condition; Using where 
2 rows in set (0.00 sec) 

ERROR: 
No query specified 

왜 첫 번째 쿼리는 비효율적이다?

+0

'SHOW CREATE TABLE'을 제공해주세요 - 선택한 색인이 무엇인지 어떻게 알 수 있습니까? –

답변

2

우선, rows의 숫자는 일부 통계 데이터를 기반으로 한 추정치이며, MySQL 버전에 따라 계획 단계에서 색인에 대한 임의의 조회가 있음을 알아 두는 것이 중요합니다. 때로는 완전히 잘못 될 수 있습니다 (이러한 예상에 따라 MySQL은 느린 실행 계획을 선택할 수도 있습니다). 이것이 MySQL이 제공하지 않는 데이터에 대해 알고 있다면, 예를 들어 쿼리를 최적화 할 수 있습니다. MySQL이 선택하기를 원하지 않는 인덱스를 강요합니다.

또한 MySQL이 최소화하려고하는 유일한 값은 전체 실행 시간입니다. 읽어야하는 행 수와 상관 관계가있을 수 있지만 (예 : filesort를 수행 할 필요가없는 경우) 필요는 없습니다. 그리고 일반적으로 좋은 전략을 선택할지라도 실제로 가장 빠르면 실제 데이터에 의존 할 수 있습니다. 예를 들어보십시오. limit 10을 사용하면 85, 4000 행 대신 검색 조건이 충족 될 것입니다. 이는 쿼리 자체가 아니라 데이터에 달려 있습니다. MySQL은 쿼리를 실행하기 전에 쿼리를 실행하는 방법을 결정해야합니다.

그러나 일반적으로 쿼리는 다른 인덱스를 사용하므로 rows에 다른 숫자가 포함될 것으로 예상됩니다.

첫 번째 쿼리는 지정된 기간의 모든 행을 통과하는 MODIFIED_TM의 인덱스를 사용합니다. 47168 행이이 범위에 있다고 추정됩니다. 이 모든 행에 대해 다른 조건에 대해 다른 열을 검사합니다.

두 번째 쿼리는 다른 열의 인덱스 (아마도 LINK_TYPE)를 사용합니다. 명확하게하기 위해 색인 정의를 추가해야합니다. URL_SHORTNER_ID이 되겠지만 다음은 색인이 LINK_TYPE 인 것으로 가정합니다. 예상치는 4950 개의 행에이 LINK_TYPE이 있습니다. 실제로는 예상치가 너무 좋으므로 예를 들어 올바른 숫자를 확인할 수 있습니다. SELECT count(*) FROM OTHERS_TINY_URL_TBL WHERE LINK_TYPE = 'BITLY'. 이 모든 행은 다른 조건과 일치하는지 확인해야합니다.

MySQL은 아직 85 개의 행만 마침내 발견 될 것이고, 4950 개의 행을 확인하고 나머지 85 개의 행을 정렬하는 것이 이미 올바른 순서로되어있는 47168 행을 확인하는 것보다 빠를 수도 있습니다. 나중에 주문할 필요가 없습니다. MySQL은 일반적으로이를 방지하기 위해 상대적으로 느린 작업입니다). 또한 행운을 얻게 될지도 모릅니다.이 47168 행 중 처음 1000 개가 이미 link_type, url_shortener_idpost_id을 수정해야하므로, 4950 행을 확인하고 정렬을 수행하는 대신 1000 행만 검사하면됩니다. 그러나 그것은 귀하의 데이터에만 의존합니다. MySQL이 제공하지 않는 데이터에 대해 알고 있다면, 예를 들어, 다른 색인을 강요하십시오. 예를 들어 MySQL을 속이거나세 번째 쿼리를 사용하여 - 실제로 하위 쿼리를 최적화해야하기 때문에 MySQL 5.7이 당신을 속일 수 있습니다.

다행히도 더 좋은 해결책이 있습니다. 첫 번째 검색어에 대한 완벽한 색인이 있습니다 (두 번째 검색어도 동시에 향상됩니다) : OTHERS_TINY_URL_TBL(URL_SHORTNER_ID, LINK_TYPE, MODIFIED_TM).