我正在尝试优化使用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.
的原因
答案 0 :(得分: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
答案 1 :(得分:0)
您似乎已使用2 sub-query's
来过滤结果,这些并非真正需要。我假设您需要显示每个latest message
ID中的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
来过滤结果,而是在Mysql中使用session vars
来保持MessageFrom
的所有消息的排名。拥有latest sendtime
的人rank
为1