2013-05-06 5 views
0

나는 MySQL EXPLAIN을 사용하여 지금까지 작성한 쿼리 중 가장 긴 쿼리를 최적화하려고 노력하고 있습니다.하지만 이것은 처음이므로 결과를 이해할 수 없습니다. 에서복잡한 쿼리 최적화

EXPLAIN SELECT pb.name, s1.MessageFrom, s1.MessageText, s1.SendTime, s1.is_unread, s1.Id, s1.autoreply_sent FROM sol_inbound s1 
    JOIN sol_contactnum c ON s1.MessageFrom = c.number 
    JOIN sol_phonebk_contactnum USING (contactnum_id) 
    JOIN sol_phonebk pb USING (phonebk_id) 
    JOIN sol_message_folder mf ON s1.Id = mf.message_id 
    WHERE (MessageFrom, SendTime) IN (SELECT MessageFrom, MAX(SendTime) FROM sol_inbound inb 
     JOIN sol_message_folder mf WHERE inb.Id = mf.message_id 
     AND mf.folder_id=1 AND mf.direction='inbound' AND mf.user_id=1 
     GROUP BY MessageFrom) 
    AND mf.folder_id=1 AND mf.direction='inbound' AND mf.user_id=1 
    UNION 
    SELECT NULL `name`, s1.MessageFrom, s1.MessageText, s1.SendTime, s1.is_unread, s1.Id, s1.autoreply_sent FROM sol_inbound s1 
    LEFT JOIN sol_contactnum c ON s1.MessageFrom = c.number 
    JOIN sol_message_folder mf ON s1.Id = mf.message_id 
    WHERE c.number IS NULL 
    AND mf.folder_id=1 AND mf.direction='inbound' AND mf.user_id=1 
    AND (MessageFrom, SendTime) IN (SELECT MessageFrom, MAX(SendTime) FROM sol_inbound inb 
     JOIN sol_message_folder mf WHERE inb.Id = mf.message_id 
     AND mf.folder_id=1 AND mf.direction='inbound' AND mf.user_id=1 
     GROUP BY MessageFrom) 
    ORDER BY SendTime DESC LIMIT 100 

EXPLAIN 결과 : 다음은 쿼리와 EXPLAIN 명령 실행의 결과 누구의 번호는 그와 전화 번호부에 표시되는 쿼리의 중간에

id select_type   table     type possible_keys             key    key_len ref              rows Extra     
------ ------------------ ---------------------- ------ ------------------------------------------------------------- ---------------- ------- ---------------------------------------------------- ------ ------------------------ 
    1 PRIMARY    pb      ALL  PRIMARY              (NULL)   (NULL) (NULL)             303       
    1 PRIMARY    sol_phonebk_contactnum ref  PRIMARY,phonebk_id1_idx,contactnum_id1_idx,phonebk_contactnum PRIMARY   4  googlep1_solane.pb.phonebk_id        1 Using index    
    1 PRIMARY    c      eq_ref PRIMARY,number_idx            PRIMARY   4  googlep1_solane.sol_phonebk_contactnum.contactnum_id  1       
    1 PRIMARY    s1      ref  PRIMARY,message_from_idx          message_from_idx 243  googlep1_solane.c.number         1 Using where    
    1 PRIMARY    mf      eq_ref PRIMARY              PRIMARY   22  const,googlep1_solane.s1.Id,const,const     1 Using where; Using index 
    2 DEPENDENT SUBQUERY inb      index PRIMARY              message_from_idx 243  (NULL)              1       
    2 DEPENDENT SUBQUERY mf      eq_ref PRIMARY              PRIMARY   22  const,googlep1_solane.inb.Id,const,const     1 Using where; Using index 
    3 UNION    s1      ALL  PRIMARY              (NULL)   (NULL) (NULL)             877 Using where    
    3 UNION    c      ref  number_idx              number_idx  243  googlep1_solane.s1.MessageFrom        1 Using where; Using index 
    3 UNION    mf      eq_ref PRIMARY              PRIMARY   22  const,googlep1_solane.s1.Id,const,const     1 Using where; Using index 
    4 DEPENDENT SUBQUERY inb      index PRIMARY              message_from_idx 243  (NULL)              1       
    4 DEPENDENT SUBQUERY mf      eq_ref PRIMARY              PRIMARY   22  const,googlep1_solane.inb.Id,const,const     1 Using where; Using index 
(NULL) UNION RESULT  <union1,3>    ALL  (NULL)               (NULL)   (NULL) (NULL)            (NULL) Using filesort   

UNION

조인 사람들은 누구 하지 마십시오 (따라서 LEFT JOIN).

편집 : 무엇이 쿼리가 수행하는 각 번호에 대한 가장 최신 인바운드 메시지를 받게하고 돌려

. 가장 오래된 메시지를 반환하기 때문에 GROUP BY을 사용할 수 있습니다. 최신이 필요합니다. 그런 다음 그것을 당신이 2를 사용하는 것 같다 그 I는 다음과 같이 WHERE c.number IS NULL.

+0

어떤 버전의 MySQL입니까? http://dev.mysql.com/doc/refman/5.7/en/using-explain.html에서 : "EXPLAIN 키워드로 명령문을 시작하면 MySQL은 쿼리 실행 계획에 대한 정보를 옵티 마이저에서 표시합니다. MySQL은 테이블 조인 방법 및 순서에 관한 정보를 포함하여 성명을 처리하는 방법을 설명합니다. " – MichaelJCox

+0

버전 5.0.10 가정합니다. 어떤 버전이든 최신 XAMPP와 함께 제공됩니다. – enchance

+1

설명 계획에 따라이 쿼리가 매우 빠릅니다. 문제가 있습니까? 나는 그 질문이 무엇인지 잘 모르겠다. –

답변

0

수, 상관되지 않은 하위 쿼리를 사용하여 확인 왜 전화 번호부에없는 번호 ...

FROM... x 
JOIN 
    (SELECT MessageFrom 
      , MAX(SendTime) max_sendtime 
     FROM sol_inbound inb 
     JOIN sol_message_folder mf 
     ON inb.Id = mf.message_id 
     WHERE mf.folder_id=1 
     AND mf.direction='inbound' 
     AND mf.user_id=1 
     GROUP 
     BY MessageFrom 
    ) y 
    ON y.messagefrom = x.messagefrom 
AND y.max_sendtime = x.sendtime 
0

합류 결과를 필터링하려면 sub-query's이 필요하지 않습니다. 각 MessageFrom ID에서 latest message을 표시해야한다고 가정합니다.

은 빠른 결과

SELECT 
    * 
FROM 
    (SELECT 
    pb.name, 
    s1.MessageFrom, 
    s1.MessageText, 
    s1.SendTime, 
    s1.is_unread, 
    s1.Id, 
    s1.autoreply_sent, 
    @row_num := IF(@prev_value=s1.MessageFrom,@row_num+1,1) AS row_num, 
    @prev_value := s1.MessageFrom 
    FROM 
    sol_inbound s1 
    JOIN sol_contactnum c ON s1.MessageFrom = c.number 
    JOIN sol_phonebk_contactnum USING (contactnum_id) 
    JOIN sol_phonebk pb USING (phonebk_id) 
    JOIN sol_message_folder mf ON s1.Id = mf.message_id 
    WHERE 
     mf.folder_id=1 
     AND mf.direction='inbound' 
     AND mf.user_id=1 
    ORDER BY 
    s1.MessageFrom, 
    s1.sendTime desc) temp WHERE temp.row_num = 1 

UNION 

SELECT 
    * 
FROM 
    (  
    SELECT 
     NULL `name`, 
     s1.MessageFrom, 
     s1.MessageText, 
     s1.SendTime, 
     s1.is_unread, 
     s1.Id, 
     s1.autoreply_sent, 
     @row_num := IF(@prev_value=s1.MessageFrom,@row_num+1,1) AS row_num, 
     @prev_value := s1.MessageFrom 
    FROM 
     sol_inbound s1 
     LEFT JOIN sol_contactnum c ON s1.MessageFrom = c.number 
     JOIN sol_message_folder mf ON s1.Id = mf.message_id 
    WHERE 
     c.number IS NULL 
     AND mf.folder_id=1 
     AND mf.direction='inbound' 
     AND mf.user_id=1 
    ORDER BY 
     s1.MessageFrom, 
     s1.sendTime desc  
     ) temp2 WHERE temp2.row_num = 1 

ORDER BY 
    SendTime DESC 
LIMIT 100 

대신 결과를 필터링 할 sub-query를 사용하는, 내가 랭크 MessageFrom의 모든 메시지를 유지하기 위해 MySQL의에서 session vars을 활용 한이보십시오. latest sendtime을 가진 컴퓨터는 rank을 가지고 있습니다. 1