我有这个选择:
select t.id, c.user, t.title, pp.foto, t.data from topics t
inner join cadastro c on t.user = c.id
left join profile_picture pp on t.user = pp.user
left join (
select c.topic, MAX(c.data) cdata from comments c
group by c.topic
)c on t.id = c.topic
where t.community = ?
order by ifnull(cdata, t.data) desc
limit 15
我想选择主题并根据主题评论的日期或日期对其进行排序(如果有评论)。
不幸的是,这需要超过9秒。
`topics` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user` INT(11) UNSIGNED NOT NULL,
`title` varchar(100) NOT NULL,
`description` varchar(1000),
`community` INT(11) UNSIGNED NOT NULL,
`data` datetime NOT NULL,
`ip` varchar(20),
PRIMARY KEY (`id`),
FOREIGN KEY (`user`) REFERENCES cadastro (`id`),
FOREIGN KEY (`community`) REFERENCES discussion (`id`)
)
`comments` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user` INT(11) UNSIGNED NOT NULL,
`comment` varchar(1000) NOT NULL,
`topic` INT(11) UNSIGNED NOT NULL,
`data` datetime NOT NULL,
`ip` varchar(20),
`delete` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
FOREIGN KEY (`user`) REFERENCES cadastro (`id`),
FOREIGN KEY (`topic`) REFERENCES topics (`id`)
)
答案 0 :(得分:3)
您的EXPLAIN
给了您强烈的暗示。该结果的第一行表示,using temporary, using filesort
暗示它没有使用索引。
可以通过添加索引和删除一些条件来改进此查询,但我认为在这种情况下存在更好的解决方案。
为什么不向topics
添加一个新列,指示上次添加评论的时间? (比如last_modified
)。每次添加评论时,只需更新该主题的列。
它实际上是非规范化的。我认为这是一个有效的用例,它总是比修复这个凌乱的查询更快。
答案 1 :(得分:3)
您正在每个查询的表comments
上执行全表扫描。它有多少行?至少创建以下索引:
comments (topic, data);
每次都避免阅读整个表格。
答案 2 :(得分:2)
我知道你说你不认为问题是索引,但是10次中有9次我遇到了这个问题,而这正是它的问题。
确保在查询中使用的每个表上创建索引,并包括在连接中指定的列。
另外,正如NiVeR所说,不要多次使用相同的别名。
这是对该查询的重构,不确定我是否混淆或错过了一个或两个列别名/别名。
select t.id, c.user, t.title, pp.foto, t.data from topics t
inner join cadastro c on t.user = c.id
left join profile_picture pp on t.user = pp.user
left join (
select com.topic, MAX(com.data) comdata from comments com
group by com.topic
)com1 on t.id = com1.topic
where t.community = ?
order by ifnull(com1.comdata, t.data) desc
limit 15