MySQL 5.7中order by created_time desc与order by -created_time的区别及性能差异
为什么
order by created_time desc和order by -created_time性能差异巨大? 现象重现
在MySQL 5.7环境下,针对1000万行数据的表执行两个逻辑结果一致的查询,耗时差异显著:
-- 耗时0.018秒 select SQL_NO_CACHE * from sample.points_full_table where created_time > '2023-01-01' order by created_time desc limit 1000;
-- 耗时5.323秒 select SQL_NO_CACHE * from sample.points_full_table where created_time > '2023-01-01' order by -created_time limit 1000;
执行计划对比
order by created_time desc执行计划:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | points_full_table | range | created_time_index | created_time_index | 5 | 4986750 | 100.00 | Using index condition |
order by -created_time执行计划:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | points_full_table | ALL | created_time_index | 9973500 | 50.00 | Using where; Using filesort |
性能差异原因解析
索引的直接复用能力
created_time_index是基于created_time字段构建的B+树索引,本身按升序存储。MySQL支持反向扫描索引,因此order by created_time desc可以直接从索引的末尾(最大的created_time值)开始向前读取,同时结合where created_time > '2023-01-01'的条件快速定位起始位置,直接取出前1000条数据,全程不需要额外排序,效率极高。计算表达式破坏索引可用性
当使用order by -created_time时,相当于对created_time执行了算术变换操作。MySQL无法直接利用现有索引来获取计算后的值的有序性,因为索引中存储的是原始created_time值,而非其负值。此时优化器无法通过索引满足排序需求,只能选择:- 先全表扫描所有数据,过滤出符合
created_time > '2023-01-01'的记录; - 对过滤后的近500万条数据执行内存/磁盘排序(即
Using filesort); - 最后取排序后的前1000条数据。
全表扫描+大规模排序的组合直接导致耗时剧增。
- 先全表扫描所有数据,过滤出符合
优化器的决策逻辑
第二个查询中,排序条件是经过计算的表达式,优化器判断无法通过索引覆盖排序需求,因此放弃使用created_time_index,转而选择全表扫描。而第一个查询的排序条件与索引完全匹配,优化器直接选择走索引,同时满足过滤、排序、取数三个需求,避免了冗余操作。
内容的提问来源于stack exchange,提问作者Andy Su
相关产品推荐
相关产品推荐

