为什么MySQL优化器会认为全表扫描比使用非聚簇索引回表更快?

千晨小哥_8328

千晨小哥_8328

2026-06-15

695人浏览

原创

mysql优化器选择聚簇索引扫描而非回表,是因为预估回表随机io总成本(≥3~5次)高于顺序扫描聚簇索引几页的i/o开销,尤其当limit 1且匹配行靠前时;统计信息cardinality偏差、索引无id导致无法复用排序、select *强制回表,均使其成本更高。

为什么mysql优化器会认为全表扫描比使用非聚簇索引回表更快?

MySQL优化器怎么算“回表 vs 聚簇索引扫描”的成本

它不看“有没有索引”,而是估算:用idx_source_id查到主键后,要回表多少次?每次回表是随机IO;而走PRIMARY是顺序扫描聚簇索引页,每页能读多行。当预估回表次数 ≥ 3~5 次,且匹配行在聚簇索引靠前位置就能命中(比如LIMIT 1),优化器就倾向选主键扫描。

关键参数来自统计信息:Cardinality决定它认为source_id = '1814613774586351713'能筛出多少行;如果该值被低估(比如实际只有1行,但统计显示有2000行),它就会高估回表开销,放弃索引。

为什么idx_source_id无法跳过排序和回表

这个索引是(source_id, source_type, state),但查询里:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • WHERE条件虽能命中前两列,但source_id是varchar(64),长度大、比较慢,且前缀重复率高,削弱了选择性
  • ORDER BY id ASC的id不在索引中,优化器无法保证按id顺序返回——它得先拿到所有匹配的id,再排序取第1个,或逐条比对
  • SELECT *要求所有字段,而索引只含source_id/source_type/state和主键id,必然触发回表

什么情况下全表扫描(实为聚簇索引扫描)反而更快

所谓“全表扫描”在InnoDB里本质是遍历PRIMARY索引叶子节点。它快的前提是:

  • 目标行物理位置靠前(比如id最小的匹配行就在前几页)
  • 过滤条件虽弱,但配合LIMIT 1能让扫描提前终止
  • 非聚簇索引的叶子节点分散存储,定位+回表的随机IO延迟 > 顺序读几页的耗时
  • 表数据页大部分已在Buffer Pool缓存中,顺序扫描几乎不触发磁盘IO

强制走索引可能更慢,别硬加USE INDEX

即使你用USE INDEX (idx_source_id)强行指定,执行时间也可能从10秒变成30秒。因为优化器的判断基于当前统计和成本常数,不是拍脑袋——它已经权衡过I/O次数、CPU比较、内存排序开销。真正有效的干预是:

  • 运行ANALYZE TABLE mapping_filter_record更新统计信息
  • 把id加进索引尾部,改成(source_id, source_type, state, id),让ORDER BY id可复用索引顺序
  • 若只查单行且source_id唯一性强,考虑建唯一索引,让优化器明确知道最多1行,降低回表预期

最易被忽略的一点:优化器看到LIMIT 1,会优先找“最早能停下来的路径”,而不是“理论上最精确的路径”。顺序扫主键一旦命中就结束,而索引+回表必须做完全部步骤才能确认结果。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4063

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

871

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1049

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5941

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2843

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5920

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7901

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1070

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

932

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程