ORDER BY使我的查询超级慢。里面的例子。加快它的想法?

时间:2012-05-29 23:18:05

标签: mysql sql performance sql-order-by

使用 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

这是 EXPLAIN

enter image description here

有什么想法吗?我愿意将它分成多个查询,创建临时表或其他任何有用的东西。这个查询正在困扰我(和我的用户)。

谢谢!

7 个答案:

答案 0 :(得分:7)

您可能需要在分数列上添加索引。

答案 1 :(得分:3)

好的,首先要做的事情是:LIMIT隐藏了大量错误查询,直到有人添加了ORDER BY - LIMIT邀请数据库引擎在生成指定数量的记录后立即保释查询,但是一旦添加了ORDER BY, ALL 记录就会在内部生成,但对程序员来说是隐藏的 - 如果LIMDER的查询因ORDER BY而大大减慢,则不是好的查询开始。

也就是说,要对您的查询(以及数据库设置)进行一些小改动以改进。通过查看EXPLAIN计划(你通过包含这个来进入前10%),一堆东西脱颖而出 - 结果集中有240,000条记录被排序。从'Using Filesort'看起来有一个2遍排序阶段正在发生,而且查询正在创建一个临时表 - 我会考虑增加你的sort_buffer_size,但要警惕让它变得太大,如同我似乎记得它的每个会话不是一个全局缓冲区,所以如果你有100个并发会话,不要把它变成256MB - 我猜4MB或8MB可能是很好的起始位置。

如果这没有大大改善我的事情,我将开始处理查询本身:EXPLAIN输出告诉我们lcase_influence索引有300多个字节键 - 如果你将影响字符串移到一个单独的tblInfluence,只需在tblInfluence.id表中包含tbluserinfluences,然后将其编入索引,然后删除tbluserinfluences表和influencename-index的大小。

如果这不能解决问题,那么我会考虑移动排序,以便它只排序所需的最小字段,而不是整个输出记录。我也会tblUsrContent直接加入tblUserInfluences - 我怀疑它不会产生太大影响,但如果是我的代码,我更喜欢单步连接到长链尽可能加入。

答案 2 :(得分:1)

好的,这是一个巨大的黑客,但我想出了一个(临时)解决问题的方法。

在搜索非常受欢迎的乐队如“粉红色的弗洛伊德”到“酷玩”时,查询速度很慢。任何不太受欢迎的乐队,查询都很快。

通过一些反复试验,我发现如果我强制查询使用 tblcontent.score 索引,那么它对于像“粉红色的弗洛伊德“,但对于像”浪漫主义者“这样不那么流行的乐队来说却很慢。

Hacky解决方案:前100名乐队的力量得分指数。让MySql对所有其他波段使用其默认值。叹。

所以粉红色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

the romantics (不太受欢迎)查询的快速版本是:

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时,这是一个不错的解决方案。我会在以后找到更优雅的东西。

答案 3 :(得分:0)

如果没有看到你的架构,我会在SCORE字段上添加一个索引。对于任何索引,INSERT都会有轻微的性能损失,但听起来像选择查询是最重要的部分。

答案 4 :(得分:0)

试试这个

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

替换???与有关的表。 我无法尝试,但我会从那开始。

答案 5 :(得分:0)

在此处更改 my.ini 文件: innodb_buffer_pool_size = 300M - 并根据您在计算机或服务器中可用的内存更改大小。对我有用!

答案 6 :(得分:0)

这就是我要做的事情

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条记录而不是排序然后限制