优化MySQL中的ORDER BY LIMIT查询

时间:2011-03-05 11:57:00

标签: php mysql sql database query-optimization

在我的网络应用程序中,我制作了一个内部邮件系统。我想在每个页面上放置一个“上一个”和一个“下一个”链接(用户查看该消息的位置)。

为了获得下一个和上一个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表示查询类型为“range”,而rows列表示它将检查id大于或小于页面id(大数字)的所有行。额外的行说“在哪里使用”。

似乎MySQL忽略了我只想要一行。 MySQL不够智能,无法优化这种查询,因此它会找到页面的行并来回搜索第一个匹配的行吗?

是否有更好的方法来获取下一页和上一页的ID?

附加说明:

  • 此问题似乎存在于每个ORDER BY LIMIT类型查询中(例如:当我将长列表拆分为多个页面时。)。
  • Where子句不是这么简单(我想让用户访问他有权访问的下一页/上一页。虽然没有加入。)
  • WHERE中的所有列都显示为索引(id是主键)
  • 保护变量免受注入。

EDIT1:

所以我目前正在使用的查询:

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))

2 个答案:

答案 0 :(得分:3)

对于之前的

SELECT MAX(id) FROM pages WHERE id<$requestPageId

接下来的

SELECT MIN(id) FROM pages WHERE id>$requestedPageId

答案 1 :(得分:1)

数据库的行为符合预期。由于小于号码(id&lt; $ requestedPageId),您的查询是范围查询。 OR语句使得使用单个索引来查找结果变得更加困难。并且,对结果进行排序意味着它必须获取所有匹配的行才能执行排序,即使您只需要1行。

您无法将其设为“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