提问人:Andrew G. Johnson 提问时间:12/7/2008 最后编辑:Andrew G. Johnson 更新时间:2/19/2012 访问量:465
MySQL 查询运行需要 >15 秒;我能做些什么来缓存/改进它?
MySQL query takes >15 seconds to run; what can I do to cache/improve it?
问:
好吧,我有一个视频网站,它的一些表格是:
标签
id ~ int(11), auto-increment [PRIMARY KEY]
tag_name ~ varchar(255)
视频标签
tag_id ~ int(11) [PRIMARY KEY]
video_id ~ int(11) [PRIMARY KEY]
视频
id ~ int(11), auto-increment [PRIMARY KEY]
video_name ~ varchar(255)
此时,tags 表有 >1000 行,videotags 表有 >32000 行。因此,当我运行查询以显示从最常见到最不常见的所有标记时,执行需要 >15 秒。
我正在使用PHP,我的代码(为简单起见,进行了淡化)如下:
foreach ($database->query("SELECT tag_name,COUNT(tag_id) AS 'tag_count' FROM tags LEFT OUTER JOIN videotags ON tags.id=videotags.tag_id GROUP BY tags.id ORDER BY tag_count DESC") as $tags)
{
echo $tags["tag_name"] . ', ';
}
现在请记住,这对我来说 100% 准确并不像快速那样重要。因此,即使查询每天执行一次,其结果在一天的剩余时间使用,我也不会在乎。
我对MySQL / PHP缓存一无所知,所以请帮忙!
答:
0赞
MarkR
12/7/2008
#1
我认为你最好的办法是创建某种汇总表,当事情发生变化时,你要维护它。
上面的查询需要扫描表中的所有行,以便找到分组中的聚合 - 没有 WHERE 子句。没有 where 子句的查询没有优化的希望,因为它必须检查每一行。
解决方法是创建一个摘要表,其中包含与该查询结果(或类似数据)相同的数据,当数据发生更改或发生重大变化时,您必须不时维护该汇总表。
只有您可以根据应用程序和数据的性质来决定是否适合按计划更新汇总表、在每次更新时更新或某种组合。
当你在做一个连接时,正确的索引仍然是有益的,但你知道这一点,对吧,并且已经这样做了?
0赞
Ólafur Waage
12/7/2008
#2
您使用的是 InnoDB 还是 MyISAM?在MyISAM中,COUNT基本上是免费的,但在InnoDB中,它必须对行进行物理计数。
评论
1赞
MarkR
12/7/2008
COUNT 仅在 MyISAM 上免费,前提是您正在计算所有行,而不是在计算组时。那么它和你预期的一样昂贵(在这种情况下,无论哪种方式,都需要扫描整个表格)
2赞
Greg
12/7/2008
#3
32,000 行仍然是一个小表——你的性能不可能那么糟糕。
你能在你的查询上运行吗 - 我猜你的索引在某处是错误的。EXPLAIN
你在问题中说:
tag_id ~ int(11) [PRIMARY KEY]
video_id ~ int(11) [PRIMARY KEY]
他们肯定是按这个顺序排列的吗?如果没有,则不会使用索引。
评论
0赞
Andrew G. Johnson
12/7/2008
好电话,它实际上是在另一个顺序。添加了一个索引,它起作用了。
3赞
Frank Krueger
12/7/2008
#4
MarkR提到了该指数。请确保:
create index videotags_tag_id on videotags(tag_id);
评论
0赞
Frank Krueger
12/7/2008
这可能和你想要调整它的速度一样快 - 任何其他速度改进都应该通过内存缓存来实现。
0赞
Eran Galperin
12/7/2008
如果将标记计数预缓存到索引列中,则可以进一步调整它。
评论