我有获取每个对话最近的消息相对基本的查询:
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秒。
你应该在哪个是你的WHERE子句中,哪些是你要选择(除了conversation_id)在列上创建多列索引。 (reference)conversation_id应在两个表中的索引。
尽量避免“或” SQL查询,这将使得取缓慢。而是使用工会或任何其他方法。
SELECT message.conversation_id,MAX(message.add_time)AS max_add_time FROM消息INNER JOIN谈话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消息INNER JOIN会话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
而不是依赖于单个表message
中,有两个表:一个用于message
,因为你,加上保留消息的线程的状态另一thread
。
是的,这增加了新的消息时,需要多一点的工作 - 在thread
更新一两栏。
但它消除了GROUP BY
和MAX
了在此查询造成的悲痛。
虽然这样做分割,看看一些列会在新表更好。
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
试试,如果你的逻辑使用它得不到影响。
您可以通过避免最大修改此查询()使用
select * from(
select row_number() over(partition by conversation_id order by add_time desc)p1
)t1 where t1.p1=1