ORDER BY 让我的查询超级慢。里面的例子。有啥加快速度的想法吗?
Posted
技术标签:
【中文标题】ORDER BY 让我的查询超级慢。里面的例子。有啥加快速度的想法吗?【英文标题】:ORDER BY makes my query super slow. Examples inside. Any ideas for speeding it up?ORDER BY 让我的查询超级慢。里面的例子。有什么加快速度的想法吗? 【发布时间】:2012-05-29 23:18:04 【问题描述】:使用 ORDER BY 运行此程序需要 10 多秒,并最终导致我的网站在高流量时崩溃。
select *
from tbluserinfluences, tblcontent, tblusers
where tblcontent.userid = tblusers.id
and tbluserinfluences.userid = tblusers.id
and tbluserinfluences.lcase_influence = 'pink floyd'
order by tblcontent.score desc
limit 0, 160
不使用 ORDER BY 运行相同的查询只需几毫秒。
select *
from tbluserinfluences, tblcontent, tblusers
where tblcontent.userid = tblusers.id
and tbluserinfluences.userid = tblusers.id
and tbluserinfluences.lcase_influence = 'pink floyd'
order by tblcontent.score desc
limit 0, 160
这里是解释
有什么想法吗?我愿意将其拆分为多个查询、创建临时表或任何其他有帮助的东西。这个查询让我(和我的用户)感到厌烦。
谢谢!
【问题讨论】:
您也可以显示您的表架构吗? SHOW CREATE TABLE tbluser 有什么影响;显示创建表 tblcontent;和 SHOW CREATE TABLE tblusers 返回?您可能需要在分数列上添加索引 你在这些表上的索引是什么? tblcontent.score 上有一个索引,但我不确定它是否有帮助或正在使用。 @eggyal 所有相关的 cmets 都已编入索引。删除 ORDER BY 使查询超快的事实让我知道(可能)所有其他索引都很好。我认为..? 【参考方案1】:您可能需要在 score 列上建立索引。
【讨论】:
分数列肯定被索引了。但是我不确定索引是否被使用。当我强制它from tbluserinfluences, tblcontent force index(score), tblusers
时,它似乎工作得更好。我会继续尝试并尽快发布我的答案(如果我弄明白的话)。
ORDER BY with the LIMIT 对我来说很可疑。这看起来可能包含一些相关信息:mysqlperformanceblog.com/2006/09/01/…
我在 5.5 和 5.1 的索引中遇到的一个问题是它对待多列索引与单列索引有很大不同。此外,如果索引列位于多个索引中,索引的处理顺序似乎发生了变化。
这里是另一个链接:explainextended.com/2009/10/23/… 请注意建议在子查询中使用 limit/order by 重写查询,以及外部连接。即在没有任何连接的情况下完成困难的部分。【参考方案2】:
好的,首先:LIMIT 隐藏大量错误查询,直到有人添加 ORDER BY - LIMIT 是在邀请数据库引擎在生成指定数量的记录后立即取消查询,但是一旦添加了 ORDER BY,ALL 记录就会在内部生成,但对程序员是隐藏的 - 如果一个 LIMIT 的查询被 ORDER BY 大大减慢,它不是很好的查询开始。
也就是说,您需要对您的查询(和数据库设置)进行一些小的更改以改善问题。通过查看 EXPLAIN 计划(包括此计划,您在前 10% 中),有很多事情很突出 - 结果集中有 240,000 条记录正在排序。从“使用文件排序”来看,似乎发生了 2 次排序阶段,而且查询正在创建一个临时表 - 我会考虑增加你的 sort_buffer_size
,但要小心不要让它太大,因为我似乎回想一下它是每个会话而不是全局缓冲区,因此如果您有 100 个并发会话,请不要将其设置为 256MB - 我猜 4MB 或 8MB 可能是不错的起始位置。
如果这不能大大改善事情,我会开始处理查询本身:EXPLAIN 输出告诉我们lcase_influence
索引有 300+ 字节键 - 如果你将影响字符串移到单独的 @987654323 @ 并且只需将tblInfluence.id
包含在tbluserinfluences
表中,并将其编入索引,那么您将同时减小tbluserinfluences
表的大小和影响名索引。
如果这不能解决问题,那么我会考虑移动排序,以便它只对所需的最小字段进行排序,而不是对整个输出记录进行排序。我还将tblUsrContent
直接加入tblUserInfluences
- 我怀疑它不会有太大的不同,但如果它是我的代码,我更喜欢单步连接而不是可能的长连接链。
【讨论】:
【参考方案3】:好的,这是一个巨大的 hack,但我想出了一个(临时)解决问题的方法。
只有在搜索“pink floyd”到“coldplay”等非常流行的乐队时,查询才会变慢。任何不那么受欢迎的乐队,查询都很快。
通过反复试验,我发现如果我强制查询使用 tblcontent.score 索引,对于像“粉红弗洛伊德”,但对于像“浪漫主义者”这样不那么受欢迎的乐队来说就慢了。
Hacky 解决方案:强制前 100 个乐队的得分指数。让 MySql 对所有其他波段使用其默认值。叹。
所以 pink floyd 查询的快速版本是:
select *
from tbluserinfluences, tblcontent FORCE INDEX(score), tblusers
where tblcontent.userid = tblusers.id
and tbluserinfluences.userid = tblusers.id
and tbluserinfluences.lcase_influence = 'pink floyd'
order by tblcontent.score desc
limit 0, 160
浪漫主义(不太流行)查询的快速版本是:
select *
from tbluserinfluences, tblcontent, tblusers
where tblcontent.userid = tblusers.id
and tbluserinfluences.userid = tblusers.id
and tbluserinfluences.lcase_influence = 'pink floyd'
order by tblcontent.score desc
limit 0, 160
当我在 Defcon 5 上时,这是一个不错的解决方案。稍后我会想出更优雅的方法。
【讨论】:
【参考方案4】:如果没有看到您的架构,我会在 SCORE 字段上添加一个索引。对于任何索引,INSERT 的性能都会受到轻微影响,但听起来选择查询对您来说是最重要的部分。
【讨论】:
【参考方案5】:试试这个
select
ui.*,
tc.*
tu.*
from tbluserinfluences as ui
LEFT JOIN tblusers AS tu ON tu.id = ui.userid
LEFT JOIN tblcontent AS tc ON tc.userid = tu.id
where ui.lcase_influence = 'pink floyd'
order by ???.score desc
limit 0, 160
替换???与有关表。 我不能尝试,但我会从那个开始。
【讨论】:
谢谢,但不幸的是,查询速度更慢(在我输入时它仍在运行,所以不确定需要多长时间才能完成)。【参考方案6】:在此处更改 my.ini 文件:innodb_buffer_pool_size = 300M - 并根据您的电脑或服务器中的可用内存更改大小。对我来说很有效!
【讨论】:
【参考方案7】:我会这样做
select * from (
select *
from tbluserinfluences, tblcontent FORCE INDEX(score), tblusers
where tblcontent.userid = tblusers.id
and tbluserinfluences.userid = tblusers.id
and tbluserinfluences.lcase_influence = 'pink floyd'
limit 0, 160) tbl
order by tbl.score desc
先限制再对160条记录排序,而不是先排序再限制
【讨论】:
我认为结果可能不如预期,因为 160 条记录不足以排序以上是关于ORDER BY 让我的查询超级慢。里面的例子。有啥加快速度的想法吗?的主要内容,如果未能解决你的问题,请参考以下文章