数据库性能问题往往隐藏在不起眼的 SQL 语句中,一条效率低下的查询可能让整个系统陷入卡顿。今天分享一套经过实战验证的优化方法论,从慢查询日志开启到 SQL 改写落地,帮你系统性解决数据库性能瓶颈。

慢查询日志:性能问题的 “黑匣子”

开启慢查询日志是优化的第一步。在 MySQL 中,通过my.cnf配置slow_query_log = 1和long_query_time = 2(单位秒),即可记录执行时间超过 2 秒的 SQL。生产环境建议将log_output设为FILE+TABLE,既保留文件日志归档,又方便通过 SQL 查询分析。

PostgreSQL 则通过postgresql.conf设置log_min_duration_statement = 2000(单位毫秒),配合log_statement = 'ddl'记录关键操作。注意日志文件需定期轮转,可通过log_rotation_size设置单个文件大小上限,避免磁盘占满。

用 explain 解码执行计划

找到慢查询后,explain命令是分析的利器。重点关注这几个字段:

  • type:显示连接类型,从好到差依次是system>const>eq_ref>ref>range>index>ALL,出现ALL意味着全表扫描,需优先优化
  • key:实际使用的索引,若为NULL则未使用索引
  • rows:估算扫描行数,数值越大性能风险越高

例如执行explain select * from orders where status=1 and create_time>'2023-01-01'时,若type显示range且key为NULL,说明需要为status和create_time建立联合索引。

10 个高频 SQL 优化案例

  1. ** 避免 SELECT ***:只查询需要的字段,减少数据传输和内存占用
  2. 用 IN 代替 OR:where id in (1,2,3)比where id=1 or id=2 or id=3更高效
  3. 优化 JOIN 顺序:小表驱动大表,select * from small t1 join large t2 on t1.id=t2.tid
  4. 索引失效场景:避免在索引列使用函数(where date(create_time)='2023-01-01')
  5. 分页优化:大数据量分页用where id>xxx limit 10代替limit 100000,10
  6. 批量操作:insert into t values(1),(2),(3)代替多条单条插入
  7. 用 exists 代替 in:where exists (select 1 from t2 where t1.id=t2.tid)更适合子表大的场景
  8. 避免 % 前缀模糊查询:like '%name'会导致索引失效,可考虑全文索引
  9. 合理使用覆盖索引:select id,name from t若有(id,name)索引,可避免回表
  10. 拆分复杂查询:将一个大查询拆分为多个小查询,利用缓存提升效率

优化 SQL 时需结合业务场景,没有放之四海皆准的方案。建议每次修改后用explain analyze对比执行时间,确保优化真实有效。记住:好的 SQL 不仅要能运行,更要跑得快、耗资源少,这需要持续的监控和迭代优化。