2013-05-06 4 views
0

Я пытаюсь оптимизировать самый длинный запрос, который я когда-либо писал, используя MySQL EXPLAIN, но поскольку это мой первый, я не могу понять результат. Вот запрос и результат от работы в 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 

The 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).

Edit:

Что этот запрос делает это получить самую последнюю Inbound сообщение для каждого номера и возвращает его. Я могу использовать GROUP BY, так как он возвращает самое старое сообщение ... Мне нужно последнее. Затем он присоединяется к ней те номера, которые не существуют в телефонной книге, поэтому я проверить 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

Это кажется вы использовали 2 sub-query's, чтобы отфильтровать результаты, они не нужны. Я предполагаю, что вам нужно отобразить latest message с каждого MessageFrom id.

Попробуйте это для более быстрых результатов

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 для фильтрации результатов, я использовал session vars в Mysql, чтобы ранг все сообщения из MessageFrom. Тот, у которого есть latest sendtime, имеет rank как 1

Смежные вопросы