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

Aus*_*tin 5 mysql indexing sql-order-by

假设我有一个非常简单的表,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

使用这个表,我想发出这样的查询:

SELECT *
FROM `t1`
ORDER BY `key_part1` ASC, `key_part2` DESC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

我曾希望ORDER BY此查询中的 索引会满意。但是,根据MySQL 文档

在某些情况下,MySQL 无法使用索引来解析ORDER BY,尽管它仍然使用索引来查找与WHERE子句匹配的行。这些案例包括:

  • 你混合ASCDESC

SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;

我尝试了一个类似于上述查询的查询,正如预期的那样,EXPLAIN输出表明这样的查询执行文件排序。这对我来说并不完全有意义,因为我可以执行以下操作:

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
Run Code Online (Sandbox Code Playgroud)

当我EXPLAIN这样做时,它说子查询和外部查询都不使用文件排序。此外,我尝试了这种具有类似结构的技巧大表,发现它使我的查询速度提高了 3 个数量级。

我的问题是

  1. 我在此处显示的两个查询是否等效?他们似乎是这样,但我可能遗漏了一些东西。如果不是,我的表中需要什么样的数据才能使它们给出不同的结果?
  2. 是否有原因 MySQL 不能自己做这个优化技巧,或者这只是一个可能的优化案例,但只是没有被写入 MySQL?

如果重要的话,我使用的是 MySQL 5.6.22。

进一步澄清:

“等效”是指“产生相同的结果”。此外,我非常清楚,如果我要更改LIMIT 1LIMIT 2或其他内容,查询将不再产生相同的结果。我对这些情况不感兴趣,只对LIMIT 1.

pet*_*cai 0

这并不是说 MySQL 缺少优化“技巧”,而是复合索引工作方式的一个特性。MySQL 一次只能在一个方向上进行索引扫描,并且必须遵循索引的排序方式(因此它可以执行计算机科学的操作,例如二分搜索等)。

让我们看看您的示例查询:

SELECT * FROM t1 WHERE key_part1= ( SELECT key_part1 FROM t1 ORDER BY key_part1ASC LIMIT 1 ) ORDER BY key_part2DESC LIMIT 1

这可以对 key_part2 进行排序,因为所有返回的行都将具有相同的 key_part1。所以基本上mysql可以忽略索引的那部分;它在功能上与 相同ORDER BY key_part1 DESC, key_part2 DESC。子查询中的方向ORDER BY无关紧要,因为它位于子查询中。

编辑

需要明确的是,您的示例查询实际上如下所示:

SELECT * FROM t1 WHERE key_part1= #{some value} ORDER BY key_part2DESC LIMIT 1

#{some value}子选择的结果在哪里。现在应该清楚为什么这种排序不需要文件排序,因为您根本没有排序key_part1。事实上,没有必要,因为所有返回的行都将具有相同的key_part1.