在 MySQL 中优化 ORDER BY LIMIT 查询
Posted
技术标签:
【中文标题】在 MySQL 中优化 ORDER BY LIMIT 查询【英文标题】:Optimizing ORDER BY LIMIT queries in MySQL 【发布时间】:2011-03-05 11:57:00 【问题描述】:在我的网络应用程序中,我制作了一个内部消息传递系统。我想在每个页面(用户查看消息的位置)上放置一个“上一个”和一个“下一个”链接。
为了获得下一个和上一个 id,我执行了两个查询:
对于上一个:
SELECT id FROM pages WHERE (id<$requestedPageId) ORDER BY id DESC LIMIT 1
对于下一个:
SELECT id FROM pages WHERE (id>$requestedPageId) ORDER BY id LIMIT 1
EXPLAIN 表示查询类型是“范围”,而 rows 列表示它将检查所有 id 小于或大于页面 id 的行(一个大数字)。 Extra 行显示“使用位置”。
似乎 mysql 忽略了我只想要一行。 MySQL 还不够聪明,无法优化这种查询,因此它会找到页面的行并前后搜索第一个匹配的行吗?
有没有更好的方法来获取下一页和上一页的 id?
补充说明:
这个问题似乎存在于每个 ORDER BY LIMIT 类型的查询中(例如:当我将一个长列表拆分为多个页面时。)。 Where 子句并非如此简单(我想让用户访问他有权访问的下一页/上一页。但不要加入。) WHERE 中出现的所有列都被索引(id 是主键) 变量受到保护以防注入。编辑1:
所以我目前使用的查询:
SELECT id
FROM reports
WHERE (id<$requestedPageId) AND ((isPublic=1) OR (recipientId=$recipient))
ORDER BY id DESC
LIMIT 1
或者当我将其重新考虑为答案时:
SELECT MAX(id)
FROM reports
WHERE (id<$requestedPageId) AND ((isPublic=1) OR (recipientId=$recipient))
【问题讨论】:
【参考方案1】:上一个
SELECT MAX(id) FROM pages WHERE id<$requestPageId
接下来
SELECT MIN(id) FROM pages WHERE id>$requestedPageId
【讨论】:
在这个简单的例子中优化了表。但是,只要我在 where 子句中添加了一个附加条件,它就会检查所有行。 (解释类型将是全部)。我将编辑我的原始帖子并输入我正在使用的查询。 您是否在 isPublic 和 recipientId 上设置了索引?【参考方案2】:数据库按预期运行。由于小于号 (id
您无法将其设为“const”类型查询,但您可以使用索引、子查询和/或联合语句对其进行优化。
这里有一个查询来统治他们。我并不是说这是最好的解决方案,而只是解决问题的一种方法。首先,如果您创建两个索引,一个在 recipientId 上,另一个在 isPublic 上,这个查询会更好地工作。
SELECT
GREATEST(
( SELECT MAX( id ) FROM reports
WHERE id < $requestedPageId AND recipientId = $recipient ),
( SELECT MAX( id ) FROM reports
WHERE id < $requestedPageId AND isPublic = 1 )
) AS prev_id
LEAST(
( SELECT MIN( id ) FROM reports
WHERE id > $requestedPageId AND recipientId = $recipient ),
( SELECT MIN( id ) FROM reports
WHERE id > $requestedPageId AND isPublic = 1 )
) AS next_id
【讨论】:
以上是关于在 MySQL 中优化 ORDER BY LIMIT 查询的主要内容,如果未能解决你的问题,请参考以下文章
MySQL优化order by导致的 using filesort