我有这个选择来获取聊天(就像facebook收件箱)。它将显示最新的消息,按发送这些消息的用户分组。
SELECT c.id, c.from, c.to, c.sent, c.message, c.recd FROM chat c
WHERE c.id IN(
SELECT MAX(id) FROM chat
WHERE (`to` = 1 and `del_to_status` = '0') or (`from` = 1 and `del_from_status` = '0')
GROUP BY CASE WHEN 1 = `to` THEN `from` ELSE `to` END
)
ORDER BY id DESC
limit 60
问题是它大约需要8秒。
`chat` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`from` int(11) UNSIGNED NOT NULL,
`to` int(11) UNSIGNED NOT NULL,
`message` text NOT NULL,
`sent` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`recd` tinyint(1) NOT NULL DEFAULT '0',
`del_from_status` tinyint(1) NOT NULL DEFAULT '0',
`del_to_status` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `from` (`from`),
KEY `to` (`to`),
FOREIGN KEY (`from`) REFERENCES cadastro (`id`),
FOREIGN KEY (`to`) REFERENCES cadastro (`id`)
)
有没有什么想法可以索引或者重写这个select来获得更好的速度?
发布于 2018-06-11 23:01:52
我假设chat.id已被编入索引。如果没有,当然你应该添加一个索引。
如果它被编入索引,那么对于子选择,MySQL通常非常慢。
您可以做的一件事是将sub _ select转换为临时表并与其连接。
它看起来会像这样
CREATE TEMPORARY TABLE IF NOT EXISTS max_chat_ids
( INDEX(id) )
ENGINE=MEMORY
AS ( 'SELECT MAX(id) as id FROM chat
WHERE (`to` = 1 and `del_to_status` = '0') or (`from` = 1 and `del_from_status` = '0')
GROUP BY CASE WHEN 1 = `to` THEN `from` ELSE `to` END' );
然后,您只需要连接临时表:
SELECT c.id, c.from, c.to, c.sent, c.message, c.recd FROM chat c
join max_chat_ids d on c.id=d.id
ORDER BY c.id DESC
limit 60
临时表只在会话期间存在,所以如果您在phpmyadmin中测试这一点,请记住执行这两个查询,并在它们之间加上';‘。
如果你尝试这样做,请分享你的结果。
发布于 2018-06-11 23:01:21
我假设列id
已经被编入索引,因为它可能是表的主键。如果不是这样,添加索引:
create index ix1_chat on chat (id);
然后,如果子查询的选择性很好,那么索引将会有所帮助。选择性是select
正在读取的行数占总行数的百分比。是50%,5%,还是0.5%?如果它是5%或更低,那么下面的索引将会有所帮助:
create index ix2_chat on chat (`to`, del_to_status, `from`, del_from_status);
顺便说一句,请不要在列名中使用保留字:我说的是来自列的。这只会让每个人的生活变得艰难。
https://stackoverflow.com/questions/50800463
复制相似问题