接口越跑越慢?保姆级 MySQL 慢 SQL 优化教程,照着做速度立刻起飞

0 阅读9分钟

平时跟很多研发、运维的朋友聊天,发现大家都在被同一个问题困扰:系统卡顿、接口超时、高峰期 CPU 直接飙满,排查来排查去,最后发现全是慢 SQL 在拖后腿。

我特别懂这种感受:赶项目的时候,图省事写个 select *,忘了建索引,测试环境看着好好的,一上生产就翻车;用户催着反馈,接口却转圈圈加载不出来,急得满头大汗;想优化又不敢改,怕手滑搞崩线上,只能硬扛,可是越扛问题越严重。

今天这篇,全是我自己总结的干货 ——保姆级 MySQL 慢 SQL 优化教程,从定位到优化,从避坑到验证,每一步都能直接照抄,新手也能大胆上手,优化完当场就能看到效果。

别被慢 SQL 坑了!3 秒判断你有没有问题

很多人不知道自己的系统是不是被慢 SQL 拖慢,教你 3 个最直观的判断方法,不用复杂工具,一眼就能看懂:

  1. 接口耗时超过 500ms,甚至一两秒,尤其是列表、查询类接口;
  2. 一到高峰期(比如电商大促、APP 推送后),系统就卡顿、超时,甚至报 500 错;
  3. 登录 MySQL,输 show processlist,能看到 Time 列几十、上百秒的 SQL,State 列显示 Copying to tmp table、Sorting result。

只要中一条,千万别犹豫,赶紧优化,早优化一天,少丢一批用户,少熬一次夜。

3 条实战命令,5 分钟找出慢 SQL

优化的前提是定位,找不到问题,瞎改就是在添乱。以下 3 条命令,是我一直用的,简单、高效,轻松上手:

1. 查看当前正在执行的慢 SQL(实时抓元凶)

show processlist;

重点看 3 个地方:

  • Time:执行时间,超过 10 秒的,直接标记为重点排查对象;
  • State:出现 Copying to tmp table(临时表复制)、Sorting result(排序)、Sending data(发送数据),基本都是慢 SQL;
  • Info:就是具体的 SQL 语句,复制下来,后续优化。

2. 开启慢查询日志(永久监控,不用手动盯)

很多人不知道慢查询日志怎么开,其实就 2 条命令,执行完永久生效(重启 MySQL 也不丢):

set global slow_query_log = 1; -- 开启慢查询日志
set global long_query_time = 1; -- 执行超过1秒的SQL,自动记录到日志里

日志默认存在 MySQL 的数据目录,文件名是 slow.log,后续想查慢 SQL,直接看这个日志就行,省了很多麻烦。

3.用 explain,一眼看穿 SQL 问题(核心中的核心)

这是最关键的一步,也是新手最容易畏难的一步。其实不用懂复杂的执行计划,就看 3 列,就能定位 80% 的问题:

explain select * from 表名 where 条件; -- 在你要排查的SQL前面加explain

重点盯 3 列,请牢记:

  • type:最关键!出现 ALL,就是全表扫描,这是慢 SQL 的头号元凶,必须优化;最好是
    ref、range,说明用到了索引,基本没问题;
  • key:显示当前 SQL 用到的索引,如果是 NULL,说明没用到索引,白加了或者写法有问题;
  • rows:MySQL 要扫描的行数,行数越多,执行越慢,优化的目标就是尽量减少这个数字。

举个我真实遇到的例子:之前一个客户,一条查询用户的 SQL,rows 显示 200 多万,type 是 ALL,明显是全表扫描,加个索引,rows 直接降到几十,执行时间从 3 秒变成 30 毫秒。

5 个硬核优化方法,照着做就提速

这些方法,是我反复验证过的,非常实用、安全,新手可以大胆操作,不用怕搞崩线上。

  1. 给 WHERE 条件加索引(提升最猛,成本最低)

这是我平时用得最多的优化方法。很多慢 SQL,就是因为查询条件没有索引,导致全表扫描。

写法直接复制,改下表名和字段名就行:

CREATE INDEX idx_字段名 ON 表名(字段名);

示例(电商订单查询,按订单号查):

CREATE INDEX idx_order_no ON `order`(order_no); -- order是关键字,要加反引号

重点提醒:只给 WHERE、ON、ORDER BY 后面的字段加索引,没用的索引别乱加(比如只用来展示的字段),不然会拖慢插入、更新速度,反而添乱。

2.避开 4 个索引失效的坑(90% 的人都踩过,包括我)

很多兄弟加了索引,发现还是慢,就是因为踩了这些坑,让索引直接失效,等于白加。这 4 个坑,我以前也踩过不少,后来记牢了,基本就不会再出错,分享给大家:

  • 坑 1:WHERE 条件里对字段用函数,比如WHERE DATE(create_time) = ‘2025-01-01’,索引直接失效;
    正确写法:WHERE create_time BETWEEN ‘2025-01-01 00:00:00’ AND ‘2025-01-01
    23:59:59’
  • 坑 2:字符串和数字混用,比如字段 phone 是 varchar 类型,查询时写WHERE phone =
    13800138000,索引失效;
    正确写法:WHERE phone = ‘13800138000’(加引号,和字段类型一致)
  • 坑 3:LIKE 查询前置百分号,比如WHERE name LIKE ‘%张三%’,索引失效;后置百分号LIKE ‘张三%’,索引有效;
  • 坑 4:用 OR 连接太多条件,比如WHERE a=1 OR b=2 OR c=3,索引会失效,能用 IN 就不用 OR,比如WHERE
    a IN (1,2,3)。

3.坚决删掉 select *(细节决定速度,别图省事)

很多朋友图省事,写 SQL 的时候直接 select *,不管需要什么字段,全查出来。看似省事,实则是性能杀手 —— 多余的字段会增加数据读取、网络传输的开销,尤其是大数据量的时候,差距特别明显。

坏写法(新手常犯):

select * from user where id = 100;

好写法(实战推荐,用什么查什么):

select id, name, phone from user where id = 100;

别小看这个细节,大数据量下,能提升 30% 以上的查询速度,还能减少数据库压力,何乐而不为。

  1. 大分页必优化(中小企业重灾区,越往后越慢)

很多系统有分页功能,比如列表页翻到 100 页之后,速度越来越慢,就是因为分页写法不对,很多人都踩过这个坑。

坏写法(新手常犯,慢到死):

select * from order limit 100000, 20;

这种写法,MySQL 会先扫描前 100020 条数据,再丢弃前 100000 条,只返回 20 条,特别耗时,数据量越大,越慢。

优化写法(我平时常用,秒出结果):

select * from order where id > 100000 limit 20;

用 id 过滤,直接定位到 100000 条之后,不用扫描前面的无效数据,速度提升几十倍,尤其是大数据量分页,效果特别明显。

5.JOIN 别超过 3 张表(小团队铁律,稳字当头)

很多兄弟为了图方便,把五六张表 JOIN 在一起,写一条复杂 SQL,看似简洁,实则数据库压力巨大。我平时优化总结的经验:JOIN 超过 3 张表,查询速度一定会明显变慢。

优化建议:能拆就拆,把一条复杂 SQL,拆成 2-3 条简单 SQL,反而更快;能冗余字段,就冗余字段(比如把用户名称冗余到订单表),牺牲一点存储空间,换查询速度,对中小企业来说,特别值。

3 条 MySQL 优化参数(直接复制)

很多时候,SQL 没问题,索引也加了,但系统还是慢,就是因为 MySQL 默认配置太保守,不适合中小企业的业务场景。这 3 条参数,直接复制到 MySQL 的 my.cnf(或 my.ini)配置文件里,重启 MySQL,数据库整体流畅度会明显提升,新手也能操作:

[mysqld] 
# 最大连接数,根据自己的业务调整,小团队1000足够 
max_connections = 1000 
# 临时表大小,避免临时表过大拖慢速度,64M足够 
tmp_table_size = 64M 
max_heap_table_size = 64M 
# 排序缓冲和连接缓冲,不用太大,2M足够,太大反而浪费内存 
sort_buffer_size = 2M 
join_buffer_size = 2M 
# 慢查询日志,前面已经开启,这里写入配置,永久生效 
slow_query_log = 1 
long_query_time = 1

提醒:修改配置后,一定要重启 MySQL 才能生效;如果不会重启,评论区问我,我一步步教你,很简单。

一条索引,救了一个电商客户

之前帮一个电商的朋友优化,他们的订单列表接口,高峰期要 3~5 秒才返回,用户投诉不断,流失严重,急得不行。

我排查后发现:一张 200 万数据的 order 表,查询订单详情时,用 order_no 作为条件,但完全没有加索引,导致每次查询都是全表扫描,CPU 直接飙到 100%。

我只做了一件事:加了一条索引,就是下面这句:

create index idx_order_no on `order`(order_no);

加完之后,接口速度直接从 3 秒降到 30 毫秒,速度提升 100 倍,高峰期也能稳定响应,朋友直接说 “救大命了”。

这就是慢 SQL 优化的真实威力 —— 不用换服务器,不用改代码,只需要找对方法,就能解决大问题。

优化慢 SQL,最容易犯的 4 个错

平时帮很多团队优化,发现大家优化慢 SQL,不是技术不行,而是思路错了,尤其是这 4 个错,几乎每个小团队都踩过,分享给大家,避坑:

  1. 乱加索引:觉得索引越多越好,结果插入、更新速度变慢,反而拖垮整个数据库;
  2. 只改 SQL,不做监控:优化完就不管了,过一段时间,慢 SQL 又出现,没人发现,最后又卡崩;
  3. 研发兼职优化,没时间深耕:研发要写代码、赶进度,优化 SQL 只是副业,很难做到专业,往往越改越乱;
  4. 高峰期不敢优化:怕改出问题,只能硬扛,结果用户流失、业务受损,反而得不偿失。