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子句匹配的行。这些案例包括:
- 你混合
ASC和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
Run Code Online (Sandbox Code Playgroud)
当我EXPLAIN这样做时,它说子查询和外部查询都不使用文件排序。此外,我尝试了这种具有类似结构的技巧大表,发现它使我的查询速度提高了 3 个数量级。
我的问题是
如果重要的话,我使用的是 MySQL 5.6.22。
进一步澄清:
“等效”是指“产生相同的结果”。此外,我非常清楚,如果我要更改LIMIT 1为LIMIT 2或其他内容,查询将不再产生相同的结果。我对这些情况不感兴趣,只对LIMIT 1.
这并不是说 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.
| 归档时间: |
|
| 查看次数: |
1646 次 |
| 最近记录: |