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

标签 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

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

SELECT *
FROM `t1`
ORDER BY `key_part1` ASC, `key_part2` DESC
LIMIT 1

我曾希望此查询中的 ORDER BY 会被索引满足。然而,根据MySQL documentation :

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. These cases include the following:

  • You mix ASC and DESC:

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

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

我的问题是

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

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

进一步说明:

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

最佳答案

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

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

选择 * 从 t1 其中 key_part1 = ( 选择 key_part1t1key_part1 升序排序 限制 1 ) 按 key_part2 降序排序 限制 1

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

编辑

需要明确的是,您的示例查询实际上看起来像这样:

选择 * 从 t1 WHERE key_part1 = #{some value} 按 key_part2 降序排序 限制 1

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

关于mysql - 如果 ASC 和 DESC 混合使用,为什么 MySQL 不能为 ORDER BY 使用索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30495388/

相关文章:

mysql - 如果用户是笔记的所有者,如何选择?数据库管理系统

php - CodeIgniter - 移动数据库元素

php - Laravel 5.4 关系不起作用无法附加第二个参数

c - 二维数组C++指针地址

mysql - 用 rand mysql 替换顺序

mysql - 安装mysql出错

mysql - 数据库表上的索引,一列公共(public)

python - 如何从 numpy 数组中快速获取特定索引?

sql - 组合排序

php - 复杂的 MySQL ORDERing : 'the' and punctuation ignored, 加数字最后