相对基本的优化JOIN和GROUP BY查询

问题描述 投票:0回答:5

我有获取每个对话最近的消息相对基本的查询:

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结果的截图:

enter image description here

原因显然是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结果:

enter image description here

我已尝试加入不同的索引来两个表没有任何的改善,例如:上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秒。

mysql sql performance indexing query-optimization
5个回答
0
投票

你应该在哪个是你的WHERE子句中,哪些是你要选择(除了conversation_id)在列上创建多列索引。 (reference)conversation_id应在两个表中的索引。


0
投票

尽量避免“或” 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


0
投票

而不是依赖于单个表message中,有两个表:一个用于message,因为你,加上保留消息的线程的状态另一thread

是的,这增加了新的消息时,需要多一点的工作 - 在thread更新一两栏。

但它消除了GROUP BYMAX了在此查询造成的悲痛。

虽然这样做分割,看看一些列会在新表更好。


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试试,如果你的逻辑使用它得不到影响。


0
投票

您可以通过避免最大修改此查询()使用

   select * from(
select row_number() over(partition by conversation_id  order by add_time desc)p1
                )t1  where t1.p1=1
© www.soinside.com 2019 - 2024. All rights reserved.