Skip to content

MySQL 中如何进行 SQL 调优? ​

  • 标签:后端、MySQL、数据库、场景题

🏛 业务架构师 ​

SQL 调优我有一套按业务优先级排的标准动作,而不是罗列技巧:

第一步:定位,用数据说话

  • 慢查询日志(long_query_time)+ pt-query-digest 聚合,按"总耗时 × 频率"排序——先治业务损失最大的,而不是最慢的那条;
  • 结合监控判断是偶发(锁等待、批量任务撞车)还是持续劣化(数据量增长)。

第二步:EXPLAIN 诊断四个信号

  • type=ALL 全表扫描、rows 远超预期:索引问题;
  • Extra 出现 Using filesort / Using temporary:排序与临时表问题,常见于 order by、group by 未命中索引;
  • key 为 NULL 或选错索引:统计信息过旧,analyze table;
  • 注意隐式类型转换、函数包裹索引列、前导模糊匹配这些"索引失效"高发写法。

第三步:按成本从低到高实施

  1. 改 SQL:明确列替代 select *、深分页改游标、大事务拆小;
  2. 改索引:联合索引调整列顺序、建覆盖索引——注意评估写放大;
  3. 改架构:读多写少的走缓存/读写分离,统计类的走 ES/ClickHouse,把查询流量迁离交易库是终极手段。

第四步:闭环机制:慢 SQL 接入告警、上线前 EXPLAIN 卡点、季度索引审计。

架构师视角的核心:调优优先级等于资损排序——支付链路的 100ms 优先于报表页的 3 秒。技术动作要贴着业务价值排期。

🏗 系统架构师 ​

SQL 调优我按"发现 → 分析 → 改写 → 验证"四步的方法论答:

发现:慢日志(long_query_time)+ pt-query-digest 聚合出 TOP SQL。

分析:EXPLAIN 看 type(至少 range,ref/eq_ref 更好)、key、rows(扫描量)、Extra(Using filesort / temporary 都是坏味道);怀疑优化器选错索引时对比 force index。

改写手段:

  • 只 select 需要的列,配合覆盖索引消回表;
  • 深度分页用延迟关联或游标(where id > x limit n);
  • 深层 or 改 union all、not in 改 not exists;join 小表驱动大表,被驱动表连接列有索引;
  • 大事务大 delete 分批(limit 循环),避免长事务与主从延迟;
  • 隐式类型转换、函数包列、前导 % 这类索引失效写法逐条治理。

验证:从库跑真实量级数据对比执行计划与耗时,用 performance_schema / slow log 确认收益。

架构视角:单 SQL 优化有天花板,量级问题要上升手段——读写分离、缓存(Redis 扛读)、ES 扛复杂查询、分库分表扛容量,SQL 调优是容量治理链路的最后一环而非唯一手段。

💻 全栈开发专家 ​

我有一套固定 SOP,比背知识点有用:

第一步:找到慢 SQL

sql
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 0.5;

配合 pt-query-digest 聚合慢日志,按"总耗时排序"而不是单次耗时,优先治理占比最高的。

第二步:EXPLAIN 诊断,我重点看四列:

  • type:ALL(全表扫)必改;index 也不行(扫整棵索引树);
  • key / key_len:走没走索引、联合索引用了几列;
  • rows:预估扫描行数,和结果集差一个数量级以上就有优化空间;
  • Extra:Using filesort(排序没走索引)、Using temporary(临时表,group by 常见)。

第三步:三板斧改写

  • 加/改联合索引(等值在前、范围在后,覆盖查询列);
  • 深分页改游标 WHERE id > ? 或延迟关联;
  • 消灭 SELECT *、隐式类型转换、索引列函数。

第四步:验证:同一条 SQL EXPLAIN FORMAT=TREE 对比,实测 RT 前后对比,别只看优化器估算。

架构层兜底:读多写少的走缓存,聚合查询挪到从库或数仓,别把 OLAP 查询打到交易库。