SQL关联查询CPU占用100%,如何排查因缺失索引导致的嵌套循环问题?
- 内容介绍
- 相关推荐
本文共计905个文字,预计阅读时间需要4分钟。
基本原因不是用了JOIN,而是执行计划选择了嵌套循环。外层驱动表返回大量行、内层被重复扫描无索引字段。每次外层返回一行,内层全表扫描一次,1万行×10万行=1亿次逻辑读,全压在CPU上做匹配和比较。
常见触发场景:LEFT JOIN 时左表没加WHERE过滤、ON条件里用了函数(如UPPER(a.name) = UPPER(b.name))、或内表连接字段完全没索引。
- MySQL默认在小结果集驱动大表时倾向
Nested Loop,但一旦驱动表实际返回行数远超预估(比如统计信息过时),就会失控 - SQL Server和Oracle也会在缺失索引+低选择性条件下 fallback 到
Nested Loops,尤其当优化器误判内表能走Index Seek却实际走了Index Scan时 - PostgreSQL在
enable_nestloop=on且无可用Hash Join路径时,同样可能硬上嵌套循环
用EXPLAIN/SHOW PLAN快速识别缺失索引的嵌套循环
别猜,直接看执行计划里有没有“Rows远大于Actual Rows”或“Missing Index提示”,以及内表访问类型是不是ALL(MySQL)、Clustered Index Scan(SQL Server)或Seq Scan(PostgreSQL)。
本文共计905个文字,预计阅读时间需要4分钟。
基本原因不是用了JOIN,而是执行计划选择了嵌套循环。外层驱动表返回大量行、内层被重复扫描无索引字段。每次外层返回一行,内层全表扫描一次,1万行×10万行=1亿次逻辑读,全压在CPU上做匹配和比较。
常见触发场景:LEFT JOIN 时左表没加WHERE过滤、ON条件里用了函数(如UPPER(a.name) = UPPER(b.name))、或内表连接字段完全没索引。
- MySQL默认在小结果集驱动大表时倾向
Nested Loop,但一旦驱动表实际返回行数远超预估(比如统计信息过时),就会失控 - SQL Server和Oracle也会在缺失索引+低选择性条件下 fallback 到
Nested Loops,尤其当优化器误判内表能走Index Seek却实际走了Index Scan时 - PostgreSQL在
enable_nestloop=on且无可用Hash Join路径时,同样可能硬上嵌套循环
用EXPLAIN/SHOW PLAN快速识别缺失索引的嵌套循环
别猜,直接看执行计划里有没有“Rows远大于Actual Rows”或“Missing Index提示”,以及内表访问类型是不是ALL(MySQL)、Clustered Index Scan(SQL Server)或Seq Scan(PostgreSQL)。

