SQL优化核心是降低磁盘IO和减少扫描行数,需结合执行计划(type/key/rows/Extra)、索引设计(最左前缀、避免冗余)及SQL写法(LIMIT、拆分查询、避免SELECT *)系统治理。

SQL优化的核心目标之一,是降低磁盘IO和减少扫描行数——这两项直接决定查询响应时间与系统吞吐能力。从运维视角看,不合理的SQL往往在高并发或大数据量场景下迅速暴露为慢查询、IO瓶颈甚至主从延迟。优化不是单纯改写SQL,而是结合执行计划、索引设计、数据分布和业务语义做系统性判断。
看清执行计划:聚焦type、key、rows、Extra
运维人员排查慢SQL的第一步,永远是EXPLAIN(或EXPLAIN FORMAT=JSON)。重点关注四项:
-
type:越靠前越好(system ≈ const > eq_ref > ref > range > index > ALL)。出现
ALL意味着全表扫描,必须干预;index虽走索引但仍是全索引扫描,同样需警惕。 - key:实际使用的索引名。为NULL说明没走索引,可能因隐式类型转换、函数包裹字段、或索引失效(如like以%开头)。
- rows:MySQL预估需要扫描的行数。该值远大于结果集行数(如查10行却扫10万行),说明索引选择不佳或过滤条件低效。
-
Extra:关注
Using filesort(排序未走索引)、Using temporary(临时表)、Using where(非索引字段参与过滤)等提示,它们常伴随额外IO开销。
索引设计要匹配查询模式,而非堆砌字段
运维中常见误区是“给WHERE里所有字段都建索引”。有效索引需满足最左前缀原则,并覆盖高频过滤+排序+分组需求:
- 单列索引只对等值查询高效;范围查询(
>、BETWEEN)后字段无法被索引利用,应把范围条件放复合索引最后。 - 排序字段若出现在
ORDER BY中,且无Using filesort,说明索引已包含有序路径,例如INDEX (a,b,c)可支持WHERE a=1 ORDER BY b,c。 - 避免冗余索引,如已有
(a,b),再建(a)意义不大;定期用sys.schema_unused_indexes(MySQL 8.0+)或慢查日志反向验证索引使用率。
减少扫描行数:从SQL写法切入
很多扫描膨胀源于SQL逻辑本身,无需改表结构也能见效:
- 用
LIMIT限制结果集,尤其分页场景:避免OFFSET过大(如LIMIT 10000,20仍要扫前10020行),改用游标分页(记录上一页最大ID)。 - 拆分复杂查询:将
JOIN + GROUP BY + ORDER BY + LIMIT大查询,拆成子查询先定位主键,再回表取详情,显著减少中间结果集大小。 - 避免SELECT *:只查必需字段,尤其避开TEXT/BLOB列——它们会强制使用磁盘临时表(
Using temporary on disk),大幅增加IO。 - 谨慎使用OR:多个OR条件易导致索引失效,可尝试改写为UNION ALL(需保证结果无重复)或使用IN替代离散值OR。
运维协同建议:监控、限流与渐进治理
优化不能只靠DBA单点发力,需与开发、测试形成闭环:
- 在SQL上线前强制要求提供
EXPLAIN结果,重点检查rows是否超阈值(如单次扫描>1万行)。 - 基于performance_schema或pt-query-digest持续采集慢日志,按
Rows_examined排序,优先处理“扫描行数/返回行数”比值异常高的SQL。 - 对历史遗留大表,启用
innodb_stats_persistent=ON并定期ANALYZE TABLE,避免统计信息过期导致执行计划劣化。 - 对无法立即优化的SQL,在代理层(如ProxySQL、ShardingSphere)或应用层配置查询超时与并发限流,防止单条SQL拖垮实例。










