我有一个相对基本的查询,可以获取每个对话的最新消息:
SELECT `message`.`conversation_id`, MAX(`message`.`add_time`) AS `max_add_time`
FROM `message`
LEFT JOIN `conversation` ON `message`.`conversation_id` = `conversation`.`id`
WHERE ((`conversation`.`receiver_user_id` = 1 AND `conversation`.`status` != -2)
OR (`conversation`.`sender_user_id` = 1 AND `conversation`.`status` != -1))
GROUP BY `conversation_id`
ORDER BY `max_add_time` DESC
LIMIT 12
message
表包含911000条以上的记录,conversation
表包含大约680000条。此查询的执行时间在4到10秒之间,具体取决于服务器上的负载。这太长了。
以下是EXPLAIN
结果的屏幕截图:
原因显然是MAX
和/或GROUP BY
,因为以下类似的查询只需要10毫秒:
SELECT COUNT(*)
FROM `message`
LEFT JOIN `conversation` ON `message`.`conversation_id` = `conversation`.`id`
WHERE (`message`.`status`=0)
AND (`message`.`user_id` <> 1)
AND ((`conversation`.`sender_user_id` = 1 OR `conversation`.`receiver_user_id` = 1))
相应的EXPLAIN
结果:
我尝试在两个表中添加不同的索引而没有任何改进,例如:conv_msg_idx(add_time, conversation_id)
message
似乎根据第一个EXPLAIN
结果使用,但查询仍然大约需要10秒钟才能执行。
非常感谢任何改进索引或查询以帮助缩短执行时间的帮助。
修改
我已将查询更改为使用INNER JOIN
:
SELECT `message`.`conversation_id`, MAX(`message`.`add_time`) AS `max_add_time`
FROM `message`
INNER JOIN `conversation` ON `message`.`conversation_id` = `conversation`.`id`
WHERE ((`conversation`.`receiver_user_id` = 1 AND `conversation`.`status` != -2)
OR (`conversation`.`sender_user_id` = 1 AND `conversation`.`status` != -1))
GROUP BY `conversation_id`
ORDER BY `max_add_time` DESC
LIMIT 12
但是执行时间仍然是~6秒。
答案 0 :(得分:0)
SELECT `message`.`conversation_id`, MAX(`message`.`add_time`) AS `max_add_time`
FROM `message`
INNER JOIN `conversation` ON `message`.`conversation_id` = `conversation`.`id`
WHERE ((`conversation`.`receiver_user_id` = 1 AND `conversation`.`status` != -2)
OR (`conversation`.`sender_user_id` = 1 AND `conversation`.`status` != -1))
GROUP BY `conversation_id`
ORDER BY `max_add_time` DESC
LIMIT 12
如果你的逻辑没有受到影响,你可以试试INNER JOIN
。
答案 1 :(得分:0)
您应该在WHERE子句中的列上创建多列索引,并且您要选择哪些列(conversation_id除外)。 (reference) conversation_id应该是两个表中的索引。
答案 2 :(得分:0)
尽量避免在Sql查询中使用'或'这会使获取速度变慢。而是使用union或任何其他方法。
SELECT message.conversation_id,MAX(message.add_time)AS max_add_time FROM message INNER JOIN conversation ON message.conversation_id = conversation.id WHERE(conversation.sender_user_id = 1 AND conversation.status!= -1))GROUP BY conversation_id 联合
SELECT message.conversation_id,MAX(message.add_time)AS max_add_time FROM message INNER JOIN conversation ON message.conversation_id = conversation.id WHERE((conversation.receiver_user_id = 1 AND conversation.status!= -2))GROUP BY conversation_id ORDER BY max_add_time DESC LIMIT 12
答案 3 :(得分:0)
您可以通过避免使用max()来修改此查询
select * from(
select row_number() over(partition by conversation_id order by add_time desc)p1
)t1 where t1.p1=1
答案 4 :(得分:0)
不是依赖于单个表message
,而是有两个表:一个用于message
,一个用于保存消息线程状态的另一个thread
。 / p>
是的,添加新邮件需要更多工作 - 在thread
更新一两列。
但它消除了导致此查询失败的GROUP BY
和MAX
。
执行此拆分时,请查看新表中是否有其他列更好。