我有这个选择来聊天(比如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`)
)
任何关于索引或重写这个选择以获得更好速度的想法?
答案 0 :(得分:1)
我假设chat.id被编入索引。如果没有,当然你应该添加一个索引。
如果它被索引,那么子选择的MySQL通常很慢。
您可以做的一件事是将您的子选择转换为临时表并加入它。
看起来像
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中进行测试,请记住同时执行两个查询&#39 ;;'它们之间。
如果您尝试分享您的结果。
答案 1 :(得分:0)
我假设列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);
作为旁注,请不要在列名中使用保留字:我正在谈论来自列。它只会让每个人的生活变得困难。