一条订单查询在测试库只需几十毫秒,切到生产后却从索引扫描退化为全表扫描:千万行表耗时从 0.2 秒升到 8 秒,逻辑读同步放大。常见误区是“索引建了就会被使用”。排查应回答三件事:执行计划实际读取了什么,候选索引的索引选择性是否足够,以及参数是否触发隐式类型转换。顺序应是先取证,再改写,而不是盲目加索引。
如果你正在选机器,或者想先把线路和配置跑通再谈长期方案,可以先看看这几家的线路说明和技术参数:speedonline(高性价比云服务),先看清带宽线路、流量策略和退款条款,再决定要不要迁。
一、先读执行计划:确认到底读了什么
先取得目标 SQL 的执行计划,核对访问类型、预估与实际行数、使用索引及过滤条件。出现全表扫描不等于索引失效:小表全扫可能更便宜,统计信息过旧也会让优化器误估成本。

把预估行数与实际行数并排比较。若估算 10 行、实际返回 100 万行,优先检查统计信息和数据分布;索引存在却未被选择,可能是代价估算偏差。还要确认过滤发生在索引扫描阶段还是取数后:即使显示索引覆盖扫描,若先扫完大量索引项再过滤,收益也可能有限。参数化 SQL 应代入典型参数,因为不同参数可能生成不同计划。
低峰期采集真实计划,记录逻辑读、耗时和返回行数,不要仅凭耗时颜色或单次快照下结论。
二、再查选择性与类型转换:定位未采用索引的原因
候选索引的选择性,可用命中行数占总行数的比例衡量。比例接近 1,过滤能力弱,优化器选择全表扫描往往合理;此时新增索引未必有效。复合索引则要结合等值条件、范围条件和列顺序评估,不能只看索引名是否存在。

如果计划显示索引扫描成本明显更低却未被采用,重点检查隐式类型转换。例如索引列是整数,查询却传入字符串,比较时可能先转换列值,使普通索引难以直接定位;转换参数列同样有成本,但要根据转换方向和计划确认。字符集、排序规则及条件外层函数也可能影响索引可用性。
低风险做法是统一参数类型、移除条件外层函数,再做等价 SQL 改写。上线前保存原 SQL、执行计划和基线指标,在影子环境或只读副本回放;上线后逐项核对计划、实际行数、逻辑读与 P95 耗时。若指标恶化,立即恢复原 SQL,并继续观察。验证多个边界参数后,才能排除计划偶然变化。
用执行计划验证索引是否真正生效
不要只凭响应时间或 key 字段判断索引是否有效,应同时观察 执行计划中的 type、possible_keys、key_len、rows、filtered 和 Extra。possible_keys 只是候选索引,最终是否使用仍以 key 为准;key_len 较短,可能说明联合索引只匹配了部分前缀;估算行数远大于实际返回行数时,还应警惕统计信息失真。执行计划出现全表扫描并不必然代表索引失效,数据占全表比例较大时,全表扫描反而可能是成本更低的方案。
索引选择性同样是关键判断依据。选择性通常可理解为不同值数量与总行数的比例,重复值过多时,索引过滤能力有限,优化器可能主动放弃它。对于联合索引,要确认查询条件符合最左前缀,并检查范围条件之后的列为何未参与过滤。若实际数据分布与统计信息差异明显,可先更新统计信息再重新比较计划,避免凭经验反复添加索引。

从类型转换、覆盖扫描到 SQL 改写
最容易踩的坑是隐式类型转换。例如字符串列与数字参数比较时,部分数据库会将索引列转换为数值,导致原本可用的索引无法被正常定位。排查时应核对字段类型、绑定参数类型、字符集和排序规则;统一应用层参数与字段类型,通常比在索引列上套函数更安全。索引列参与计算、拼接或使用 LIKE '%关键字' 时,也会破坏索引定位能力。
当查询只读取索引中已有的列和条件列时,可以尝试形成索引覆盖扫描。执行计划中的 Using index 表示无需回表读取数据行,但它不代表扫描范围一定很小;低选择性条件仍可能读取大量索引项。对于复杂查询,可将无法有效索引的表达式移到常量一侧,把过滤条件拆成可搜索条件,或使用 EXISTS、UNION ALL 等方式改写 SQL。改写前后必须比较结果集、并发表现和执行计划,不能只为“让索引出现”而牺牲语义。
可执行检查清单:①保存原始 SQL、参数和执行计划;②使用 EXPLAIN ANALYZE 对照估算行数与实际行数;③检查索引列类型、字符集及参数绑定类型;④确认联合索引的匹配前缀与范围边界;⑤排除隐式转换、函数包裹和前导通配符;⑥评估能否改成覆盖扫描并减少回表;⑦用等价 SQL 改写后复测 P95、扫描行数及临时表开销;⑧持续采集慢查询与计划变化,防止统计信息过期或数据增长再次引发失效。


喜欢
顶
难过
囧
围观
无聊





