某线上接口响应时间高达 50秒以上,频繁超时,严重影响用户体验。测试环境却运行流畅,引发了排查行动。
✅ 1. 链路追踪识别慢接口
通过链路追踪系统(如 SkyWalking)快速定位到是某数据库查询拖慢了接口响应。
✅ 2. 日志 + SQL 拦截器打印完整 SQL
结合 MyBatis 的 SQL 拦截器,拿到完整参数拼接后的 SQL:
SELECT MAX(t.id)
FROM user_log t
WHERE t.deleted_at = '1970-01-01 00:00:00'
AND LENGTH(t.platform_id) > 0
AND t.platform_id != '0'
AND t.platform_type = 'MOBILE'
AND t.nickname LIKE CONCAT('%', 'abc', '%')
GROUP BY t.platform_id
LIMIT 20;
✅ 3. 执行计划分析(EXPLAIN)
发现生产环境错误命中了一个 deleted_at 开头的索引:
idx_deletedat_memberaccountid_updatedat
→ 扫描行数:2,126,736
→ filesort + 临时表
→ 总耗时:50秒
而测试环境使用了更合适的索引 idx_platformtype_deletedat_platformid_nickname,执行仅需数百毫秒。
优化器在生产环境中误判了最优索引,导致全表扫描 + 临时表排序。
原因如下:
条件字段 | 测试环境匹配量级 | 生产环境匹配量级 |
---|---|---|
deleted_at | 千级(约 5,000) | 百万级(约 2,100,000) |
platform_type | 十万级(约 700,000) | 百万级(约 1,250,000) |
💡推断结果:生产环境中 deleted_at 匹配数据过多,导致优化器错误判断为过滤性强字段,选择了 sub-optimal 的索引。
✅ 方案一:条件性使用 USE INDEX
MyBatis XML 中动态注入:
<if test="ro.platformType != null and ro.partialNickname != null and ro.talentPlatformIdList == null">
USE INDEX (idx_platformtype_deletedat_platformid_nickname)
</if>
作用:
• 避免在昵称列表查询、没有 platform_id 精确范围时优化器选错;
• 限制性注入,确保只在特定组合下才强制索引,避免一刀切。
✅ 方案二:范围优化替换函数过滤
替换原本的冗余判断逻辑:
-- 原来
AND LENGTH(t.platform_id) > 0 AND t.platform_id != '0'
-- 优化后
AND t.platform_id > '0'
优势:
环境 | 优化前 | 优化后 | 提升倍数 |
---|---|---|---|
生产环境 | ~50 秒 | ~0.9 秒 | 55x |
以下是在当前方案基础上,总结出的更进一步的可选优化方向,适合后续演进考虑,目前先不继续优化,因为下面的ROI太低。
ALTER TABLE some_table ADD FULLTEXT INDEX idx_nickname_ft (nickname);
SELECT ... FROM some_table
WHERE MATCH(nickname) AGAINST('+abc' IN BOOLEAN MODE);
WHERE platform_id IN (...) OR home_link IN (...)
(SELECT ... FROM ... WHERE platform_id IN (...))
UNION ALL
(SELECT ... FROM ... WHERE home_link IN (...))
ANALYZE TABLE some_table UPDATE HISTOGRAM ON platform_type WITH 256 BUCKETS;
🎯 优化关键词:
• USE INDEX 条件控制
• 函数过滤改范围判断
• 分析数据分布差异
• 关注优化器行为
• 精准条件下强引导,避免全局强绑
🧠 经验总结:
建议 | 说明 |
---|---|
优化前务必 EXPLAIN 对比 | 理解生产 vs 测试为何差异巨大 |
慎用函数包裹索引字段 | 函数过滤常导致索引失效 |
条件性 USE INDEX 而非全局固定 | 提高兼容性与鲁棒性 |
字段分布决定优化器行为 | 不同环境需分别调优 |
⸻
一次错误的索引选择,能将查询放大 50 倍耗时;一次精细的微调组合,就能让系统重获新生。
面对优化器,别“全信”,也别“硬刚”,用更细致的策略去协同它,才是高阶的 SQL 优化之道。