简体   繁体   English

如果ASC和DESC混合使用,为什么MySQL不能使用ORDER BY的索引?

[英]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 the WHERE clause. 在某些情况下,MySQL不能使用索引来解析ORDER BY ,尽管它仍然使用索引来查找与WHERE子句匹配的行。 These cases include the following: 这些案例包括以下内容:

  • You mix ASC and DESC : 你混合ASCDESC

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 我的问题是

  1. Are the two queries I show here equivalent? 我在这里展示的两个查询是否相同? They seem like they are, but I may be missing something. 它们看起来像是,但我可能会遗漏一些东西。 If they are not, what kind of data would I need to have in my table to cause them to give different results? 如果不是,我需要在表格中提供哪种数据才能使它们得到不同的结果?
  2. Is there a reason that MySQL can't do this optimization trick on it's own, or is this just a case of an optimization that is possible, but just hasn't been written into MySQL? 有没有理由说MySQL不能自己做这个优化技巧,或者这只是一个可能的优化案例,但是还没有写入MySQL?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM