上一题下一题

同一条 SQL 在测试环境执行很快,生产环境却出现全表扫描,你会如何从统计信息、数据分布、参数差异和执行计划变化进行排查?

免费版
来源:MySQL 调优场中级工程师数据库统计信息与数据分布联合索引设计执行计划分析MySQL慢查询排查
草稿该题目为草稿状态,前台公开题库中不可见。
答案解析

我会先确认两套环境执行的确实是同一条 SQL,包括 SQL 文本、绑定参数、数据库版本、表结构、索引以及会话级优化参数,避免只是表面上 SQL 一样,实际执行条件不同。

排查时我会重点看以下几个方面:

1. 先对比执行计划

在测试和生产环境分别使用 EXPLAIN 或数据库对应的实际执行计划工具,重点比较访问路径、是否命中索引、驱动表选择、连接顺序、预估行数和实际行数、扫描行数以及谓词是否下推。

如果生产环境出现全表扫描,需要确认是优化器主动认为全表扫描成本更低,还是索引没有被使用。例如索引列上存在函数、隐式类型转换、前导模糊匹配,或者索引选择性太差,都会导致索引无法有效使用。

2. 检查统计信息是否过期或不准确

优化器主要依赖统计信息估算数据量和选择性。如果生产环境经历过大量数据导入、删除或更新,但没有及时更新统计信息,优化器可能误判过滤条件返回的行数,从而选择全表扫描。

我会对比两边表和索引的统计信息更新时间、表行数、索引基数、直方图等信息,并检查是否开启了自动收集统计信息。必要时在业务允许的情况下重新收集表和索引统计信息,然后重新观察执行计划。不过统计信息更新要评估对线上资源和计划稳定性的影响,不能直接在高峰期执行。

3. 检查数据分布和索引选择性

测试环境的数据量和分布通常与生产差异很大。比如测试库有几十万行,某个状态字段只有少量数据;生产库有几亿行,状态字段大部分都是同一个值。此时即使有索引,按照这个低选择性字段过滤也可能需要访问大量数据,优化器会认为全表扫描更划算。

我会分别统计生产和测试环境中条件字段的基数、各个值的分布、目标条件实际返回的行数,以及联合索引中字段的组合分布。如果是数据倾斜导致的估算错误,可以考虑补充直方图、调整联合索引顺序、增加更有区分度的过滤条件,或者结合业务场景优化索引设计。

4. 确认绑定参数和参数嗅探问题

即使 SQL 模板相同,参数不同也可能导致不同计划。例如某个参数只匹配几十行,另一个参数能匹配几千万行,前者适合走索引,后者可能适合全表扫描。

如果数据库存在参数嗅探或绑定变量窥探机制,还可能出现第一次执行时生成的计划被后续请求复用,导致某些参数使用了不合适的执行计划。我会分别使用测试环境和生产环境的真实参数执行,并检查是否存在参数类型不一致、参数长度差异、隐式转换以及极端参数值。

5. 检查执行计划是否发生了缓存或版本变化

我会确认生产环境是否存在历史执行计划、固定计划、SQL Plan Baseline、Hint,或者因为统计信息变化、索引变化、数据库升级、参数配置变化而重新生成了计划。同时也要关注执行计划缓存是否因重启、内存压力或 DDL 操作发生变化。