Оптимизация сложного запроса

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

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 так как он возвращает самое старое сообщение... мне нужно самое последнее. Затем он соединяет эти номера, которых нет в телефонной книге, поэтому я проверяю WHERE c.number IS NULL.

2 ответа

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

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

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

Где возможно, используйте некоррелированный подзапрос следующим образом...

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
Другие вопросы по тегам