[英]Why can't MySQL use an index for ORDER BY if ASC and DESC are mixed?
Let's say I have a very simple table like this: 假设我有一个非常简单的表,如下所示:
CREATE TABLE `t1` (
`key_part1` INT UNSIGNED NOT NULL,
`key_part2` INT UNSIGNED NOT NULL,
`value` TEXT NOT NULL,
PRIMARY KEY (`key_part1`, `key_part2`)
) ENGINE=InnoDB
Using this table, I want to issue a query like this: 使用此表,我想发出这样的查询:
SELECT *
FROM `t1`
ORDER BY `key_part1` ASC, `key_part2` DESC
LIMIT 1
I had hoped that the ORDER BY
in this query would get satisfied by the index. 我曾希望索引能满足此查询中的
ORDER BY
。 However, according to the MySQL documentation : 但是,根据MySQL文档 :
In some cases, MySQL cannot use indexes to resolve the
ORDER BY
, although it still uses indexes to find the rows that match theWHERE
clause.在某些情况下,MySQL不能使用索引来解析
ORDER BY
,尽管它仍然使用索引来查找与WHERE
子句匹配的行。 These cases include the following:这些案例包括以下内容:
- You mix
ASC
andDESC
:你混合
ASC
和DESC
:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
I tried a query similar to the above query and as expected, the EXPLAIN
output says that such a query does a filesort. 我尝试了类似于上面的查询的查询,并且正如预期的那样,
EXPLAIN
输出说这样的查询执行文件排序。 This doesn't totally make sense to me because I can do the following: 这对我来说并不完全有意义,因为我可以做到以下几点:
SELECT *
FROM `t1`
WHERE `key_part1` = (
SELECT `key_part1`
FROM `t1`
ORDER BY `key_part1` ASC
LIMIT 1
)
ORDER BY `key_part2` DESC
LIMIT 1
When I EXPLAIN
this, it says both the subquery and the outer query do not use a filesort. 当我
EXPLAIN
这一点,它说这两个子查询和外部查询不使用文件排序。 Furthermore, I tried this kind of trick big table I have with a similar structure and found that it speeds up my query by 3 orders of magnitude. 此外,我尝试了这种具有类似结构的技巧大表,并发现它将我的查询加速了3个数量级。
My questions are 我的问题是
If it matters, I am using MySQL 5.6.22. 如果重要,我使用的是MySQL 5.6.22。
Further clarification: 进一步澄清:
By "equivalent" I mean "produce the same result". “等价”我的意思是“产生相同的结果”。 Additionally, I am very aware that if I were to change
LIMIT 1
to LIMIT 2
or something, the queries would no longer produce the same results. 另外,我非常清楚如果我将
LIMIT 1
更改为LIMIT 2
或其他什么,查询将不再产生相同的结果。 I am not interested in those cases, only in the case with LIMIT 1
. 我对这些情况不感兴趣,仅限
LIMIT 1
。
It's not that MySQL is missing an optimization "trick", it's a property of how compound indexes work. 这不是MySQL缺少优化“技巧”,它是复合索引如何工作的属性。 MySQL can only do an index scan in one direction at a time, and has to go with how the index is ordered (so it can do computer-sciency things like binary search, etc).
MySQL一次只能在一个方向上进行索引扫描,并且必须考虑索引的排序方式(因此它可以进行计算机验证,如二进制搜索等)。
Let's look at your sample query: 我们来看看你的示例查询:
SELECT * FROM t1
WHERE key_part1
= ( SELECT key_part1
FROM t1
ORDER BY key_part1
ASC LIMIT 1 ) ORDER BY key_part2
DESC LIMIT 1 SELECT * FROM
t1
WHERE key_part1
=(SELECT key_part1
FROM t1
ORDER BY key_part1
ASC LIMIT 1)ORDER BY key_part2
DESC LIMIT 1
This can order on key_part2 because all returned rows will have an identical key_part1. 这可以在key_part2上订购,因为所有返回的行都具有相同的key_part1。 So basically mysql can ignore that part of the index;
所以基本上mysql可以忽略那部分索引; it is functionally identical to
ORDER BY key_part1 DESC, key_part2 DESC
. 它在功能上与
ORDER BY key_part1 DESC, key_part2 DESC
。 The direction of the ORDER BY
in your subquery is irrelevant because it was in a subquery. 子查询中
ORDER BY
的方向无关紧要,因为它位于子查询中。
Edit 编辑
To be clear, your example query really looks like this: 要清楚,您的示例查询看起来像这样:
SELECT * FROM t1
WHERE key_part1
= #{some value} ORDER BY key_part2
DESC LIMIT 1 SELECT * FROM
t1
WHERE key_part1
=#{some value} ORDER BY key_part2
DESC LIMIT 1
Where #{some value}
is the result of a subselect. 其中
#{some value}
是subselect的结果。 It should be clear now why this sort doesn't need a filesort, because you are not sorting by key_part1
at all. 现在应该清楚为什么这种类型不需要文件排序,因为你根本没有按
key_part1
排序。 In fact, there is no need to, because all returned rows will have identical key_part1
. 实际上,没有必要,因为所有返回的行都具有相同的
key_part1
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.