MySQL不同返回结果的SELECT查询耗时异常问题咨询
问题描述
我有一张约7000行数据的简单表,对其执行完全相同的WHERE条件的MySQL查询10000次,仅修改SELECT子句的返回内容,结果耗时差异远超预期:原本以为返回固定值SELECT 1的查询最快,返回全量字段SELECT *的最慢,但实际结果完全相反。
MySQL版本为5.7.40。
单次测试耗时
- 4.5993759632111 秒
SELECT * FROM mytable WHERE 145109811 BETWEEN start AND end LIMIT 1
- 5.3308868408203 秒
SELECT ID FROM mytable WHERE 145109811 BETWEEN start AND end LIMIT 1
- 7.7556929588318 秒
SELECT 1 FROM mytable WHERE 145109811 BETWEEN start AND end LIMIT 1
三轮重复测试结果
为排除数据库状态影响,将三种查询放入同一脚本,按不同顺序执行三轮测试:
第一轮顺序:SELECT 1 → SELECT * → SELECT ID
10:19:58 - SELECT 1 - 7.3224468231201 sec. 10:20:03 - SELECT * - 4.6961460113525 sec. 10:20:08 - SELECT ID - 4.4760630130768 sec. 10:20:28 - SELECT 1 - 7.4960129261017 sec. 10:20:32 - SELECT * - 4.4980108737946 sec. 10:20:37 - SELECT ID - 4.4355578422546 sec. 10:21:00 - SELECT 1 - 8.0782158374786 sec. 10:21:04 - SELECT * - 4.4764659404755 sec. 10:21:09 - SELECT ID - 4.273129940033 sec.
第二轮顺序:SELECT * → SELECT ID → SELECT 1
10:22:23 - SELECT * - 6.5342800617218 sec. 10:22:28 - SELECT ID - 5.1359310150146 sec. 10:22:35 - SELECT 1 - 7.1028819084167 sec. 10:22:52 - SELECT * - 4.8350520133972 sec. 10:22:57 - SELECT ID - 4.4192798137665 sec. 10:23:04 - SELECT 1 - 6.9962570667267 sec. 10:23:18 - SELECT * - 5.2138640880585 sec. 10:23:22 - SELECT ID - 4.3040509223938 sec. 10:23:30 - SELECT 1 - 7.1998341083527 sec.
第三轮顺序:SELECT ID → SELECT 1 → SELECT *
10:24:05 - SELECT ID - 4.7385289669037 sec. 10:24:12 - SELECT 1 - 7.1701371669769 sec. 10:24:17 - SELECT * - 4.5180490016937 sec. 10:24:33 - SELECT ID - 5.6322748661041 sec. 10:24:41 - SELECT 1 - 7.4376618862152 sec. 10:24:45 - SELECT * - 4.4281830787659 sec. 10:25:00 - SELECT ID - 5.3789880275726 sec. 10:25:07 - SELECT 1 - 7.3066239356995 sec. 10:25:12 - SELECT * - 4.5297379493713 sec.
总耗时统计
SELECT * 39.03364301 sec. SELECT ID 42.79380441 sec. SELECT 1 66.11007166 sec.
原因分析
这种反直觉的结果主要和MySQL 5.7的执行引擎处理逻辑、聚簇索引特性有关,具体可以从这几个角度解释:
1. 聚簇索引的直接读取优势
你的表是InnoDB引擎(默认),主键ID对应的聚簇索引叶子节点存储了整行数据:
- 执行
SELECT *时,找到符合BETWEEN条件的行后,直接从聚簇索引叶子节点读取整行数据返回,不需要额外IO或数据拼接。 - 执行
SELECT ID时,虽然只需要主键值,但同样是直接从聚簇索引读取,不过服务器层需要过滤掉其他列,有极少量额外开销,所以比SELECT *稍慢。
而SELECT 1的情况,MySQL找到符合条件的行后,不能直接从索引/数据行中读取现成的值,需要服务器层动态生成常量1返回。这个生成操作单次开销极小,但在10000次重复执行的场景下,累积的开销就会被放大,导致总耗时显著增加。
2. 优化器的执行计划差异
在MySQL 5.7中,对于SELECT 1这类返回常量的查询,优化器可能不会触发和SELECT */SELECT ID相同的“快速返回”优化:
- 虽然三个查询都用了
LIMIT 1,找到第一个符合条件的行就停止扫描,但SELECT 1的执行流程中,服务器层需要额外处理“常量生成”的逻辑,导致每个查询的执行周期变长。 - 对比之下,
SELECT *和SELECT ID都是直接读取已有数据,执行流程更简洁,单查询耗时更短。
3. 缓存与执行上下文的影响
虽然你做了多轮不同顺序的测试,但SELECT *和SELECT ID的结果是从聚簇索引读取的实际数据,更容易被MySQL的缓存机制(如InnoDB缓冲池)命中;而SELECT 1返回的是动态生成的常量,无法利用数据缓存的优势,每次执行都需要重新生成,进一步拉开了耗时差距。
内容的提问来源于stack exchange,提问作者Junior
相关产品推荐
相关产品推荐

