[英]Optimizing ORDER BY LIMIT queries in MySQL
In my web app I made an internal messaging system. 在我的网络应用程序中,我制作了一个内部邮件系 I want to place a 'previous' and a 'next' link on each page (where the user viewing the message).
我想在每个页面上放置一个“上一个”和一个“下一个”链接(用户查看该消息的位置)。
In order to get the next and previous id I execute two queries: 为了获得下一个和上一个id,我执行两个查询:
For the previous one: 对于前一个:
SELECT id FROM pages WHERE (id<$requestedPageId) ORDER BY id DESC LIMIT 1
And for the next one: 对于下一个:
SELECT id FROM pages WHERE (id>$requestedPageId) ORDER BY id LIMIT 1
EXPLAIN says the the query type is "range" and the rows column says it would examine all rows that has smaller or bigger id than the page's id (a big number). EXPLAIN表示查询类型为“range”,而rows列表示它将检查id大于或大于页面id(大数字)的所有行。 The Extra row says "Using where".
额外的行说“在哪里使用”。
It seems MySQL ignores that I want only one row. 似乎MySQL忽略了我只想要一行。 Isn't MySQL smart enough to optimize this kind of query so it would find the row for the page and search for the first matching row back/forth?
MySQL不够智能,无法优化这种查询,因此它会找到页面的行并来回搜索第一个匹配的行吗?
Is there a better approach to get the next and previous page's id? 是否有更好的方法来获取下一页和上一页的ID?
Additional notes: 补充笔记:
EDIT1: EDIT1:
So the query I'm using currently: 所以我目前正在使用的查询:
SELECT id
FROM reports
WHERE (id<$requestedPageId) AND ((isPublic=1) OR (recipientId=$recipient))
ORDER BY id DESC
LIMIT 1
Or when I re-factor it as the answer said: 或者当我重新考虑它时,答案说:
SELECT MAX(id)
FROM reports
WHERE (id<$requestedPageId) AND ((isPublic=1) OR (recipientId=$recipient))
For the previous 对于以前
SELECT MAX(id) FROM pages WHERE id<$requestPageId
And for the next 并为下一个
SELECT MIN(id) FROM pages WHERE id>$requestedPageId
The database is behaving as expected. 数据库的行为符合预期。 Your query is a range query because of the less-than symbol (id < $requestedPageId).
由于小于号码(id <$ requestedPageId),您的查询是范围查询。 The OR statement makes it harder to use a single index to find the results.
OR语句使得使用单个索引来查找结果变得更加困难。 And, sorting the results means it has to get all matching rows to perform the sort, even though you only want 1 row.
并且,对结果进行排序意味着它必须获取所有匹配的行才能执行排序,即使您只需要1行。
You're not going to be able to make this a "const" type query, but you may be able to optimize it using indexes, sub-queries, and/or union statements. 您无法将其设置为“const”类型查询,但您可以使用索引,子查询和/或联合语句对其进行优化。
Here is one query to rule them all. 这是一个统治它们的查询。 I'm not saying this is the best solution, but just one way of approaching the problem.
我不是说这是最好的解决方案,而只是解决问题的一种方法。 To start, this query will work better if you create two indexes, one on recipientId and another on isPublic.
首先,如果您创建两个索引,此查询将更好地工作,一个在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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.