当前位置: 首页 > news >正文

慢SQL优化实战教学

文章目录

  • 一、先搞懂:什么样的SQL才算「慢SQL」?
    • 1.1 生产慢SQL判定标准(通用标准)
  • 二、慢SQL第一步:永远先定位,再优化(别瞎改SQL)
    • 2.1 必用神器:explain 执行计划
    • 2.2 explain 只要看3个核心字段(新手够用)
      • ① type 字段(最关键)
      • ② key 字段
      • ③ rows 字段
  • 三、核心根源:99%慢SQL就这几大原因
  • 四、索引优化:优化慢SQL最见效、提升最快
    • 4.1 哪些字段必须建索引?
    • 4.2 索引最左匹配原则(必记)
    • 4.3 索引失效十大坑(日常开发最容易踩)
  • 五、SQL写法规范优化(改完立马提速)
    • 5.1 永远禁止 select *
    • 5.2 小表驱动大表,join别乱连
    • 5.3 尽量避免子查询,改成join
    • 5.4 limit 深度分页一定要优化
  • 六、业务层面优化(最高级、最有效)
    • 6.1 大查询、统计、报表别查主库
    • 6.2 热点数据、高频查询全部放Redis
    • 6.3 大表一定要分库分表
  • 七、生产慢SQL优化标准流程(照着这个步骤排查)
  • 八、最终总结一句话

一、先搞懂:什么样的SQL才算「慢SQL」?

不是报错的SQL才叫有问题,执行时间长、扫描行数多、返回数据少,就是慢SQL。

1.1 生产慢SQL判定标准(通用标准)

  • 单条SQL执行时间超过1秒:算轻微慢查询;

  • 单条SQL执行时间超过3秒:线上必须优化;

  • 扫描行数几十万、上百万,结果只返回几十条:典型烂SQL,必优化。

核心本质:扫描的数据太多,真正用到的数据太少,全是无效IO、无效计算。

二、慢SQL第一步:永远先定位,再优化(别瞎改SQL)

优化慢SQL,千万别上来就改代码。不改explain的优化,都是瞎优化。

2.1 必用神器:explain 执行计划

任何慢SQL,前面加个explain,一眼看出问题在哪。

explainSELECT*FROMuserWHEREname='张三';

2.2 explain 只要看3个核心字段(新手够用)

① type 字段(最关键)

查询类型,好坏级别:system > const > eq_ref > ref > range > index > ALL

生产红线:绝对不能出现 ALL,ALL就是全表扫描,数据一多必慢。

② key 字段

真正用到的索引。key为null = 没走索引,直接全表扫描。

③ rows 字段

扫描了多少行。扫描行数越大,SQL越慢。

优化核心目标:type别为ALL,key要有索引,rows尽量小。

三、核心根源:99%慢SQL就这几大原因

  1. 没加索引:查询字段、条件字段没建索引,全表扫描;

  2. 索引失效:建了索引,写法不对,索引作废;

  3. select * 乱查:查一堆用不着的字段,不走覆盖索引,大量回表;

  4. join、子查询乱用:大表连大表,笛卡尔积爆炸;

  5. 分页深度过大:limit 100000,10 经典大坑;

  6. 业务逻辑不合理:数据库干了不该干的事,排序统计全压给SQL。

四、索引优化:优化慢SQL最见效、提升最快

4.1 哪些字段必须建索引?

一句话:WHERE、JOIN、ORDER BY、GROUP BY 后面的字段,必须建索引。

4.2 索引最左匹配原则(必记)

联合索引\(a,b,c\)

  • 查 where a=? 走索引;

  • 查 where a=? and b=? 走索引;

  • 只查 b=? 或 c=? 索引直接失效

索引带头大哥不能丢,丢了就不走索引。

4.3 索引失效十大坑(日常开发最容易踩)

只要踩中,索引直接作废,全表扫描:

  1. select * 不用覆盖索引;

  2. 索引字段做运算、函数:where age\+1=20

  3. 隐式类型转换:字符串字段用数字查询;

  4. like %xxx 左模糊查询;

  5. or 两边字段不同时加索引;

  6. not in、not exists 反查逻辑;

  7. order by 字段没在索引最后;

  8. 数据量太少、mysql觉得走索引不如全表快;

  9. 隔离级别、锁冲突导致索引优化失效;

  10. 长时间长事务不提交,索引缓存异常。

五、SQL写法规范优化(改完立马提速)

5.1 永远禁止 select *

只查需要的字段,能走覆盖索引就不用回表查询数据,性能直接差十倍起步

很多人习惯随手写SELECT *,看似省事,实则把没必要的大字段(备注、文本、创建时间等)全部查出来,不仅增加磁盘IO、网络传输,还直接导致索引覆盖失效,必须回表捞数据,越查越慢。

-- 烂写法:查所有字段,不走覆盖索引,必然回表,性能极差SELECT*FROM`order`WHEREuser_id=1001;-- 优化写法:只查业务需要字段,命中覆盖索引,无需回表,速度飞快SELECTid,order_no,pay_price,create_timeFROM`order`WHEREuser_id=1001;
-- 垃圾SELECT*FROMorderWHEREuser_id=1001;-- 推荐SELECTid,order_no,priceFROMorderWHEREuser_id=1001;

5.2 小表驱动大表,join别乱连

join 两张表:小表放左边,大表放右边,减少循环匹配次数。

禁止大表连大表,禁止三张以上表join,关联越多,匹配逻辑越复杂,临时表开销越大。

核心原则:数据量小的小表当驱动表,先循环小表;数据量大的大表当被驱动表,只做精准匹配,减少整体循环匹配次数,JOIN性能直接翻倍。

-- 烂写法:大表驱动小表,循环次数多,匹配效率低SELECT*FROMbig_order_table bLEFTJOINsmall_user_table sONb.user_id=s.id;-- 优化写法:小表驱动大表,精准匹配,减少循环扫描SELECTo.id,o.order_no,s.usernameFROMsmall_user_table sLEFTJOINbig_order_table oONs.id=o.user_idWHEREs.id=1001;

5.3 尽量避免子查询,改成join

子查询运行时会自动生成临时表,临时表没有索引,查询匹配全靠遍历,数据量大了巨慢。生产实战里,能用JOIN关联查询,一律不用子查询

-- 烂写法:使用子查询,生成无索引临时表,查询低效SELECT*FROM`order`WHEREuser_idIN(SELECTidFROM`user`WHERElevel=1);-- 优化写法:改成JOIN关联查询,直接走已有索引,无临时表开销SELECTo.id,o.order_noFROM`order`oINNERJOIN`user`uONo.user_id=u.idWHEREu.level=1;

5.4 limit 深度分页一定要优化

limit 100000,10数据库要先扫10万行,再丢弃,巨慢。

优化核心方案:先靠主键索引做快速分页定位,再关联查询其他字段,避免扫描大量无效数据,深度分页性能提升几十倍。

-- 烂写法:深度分页,先扫10万行再丢弃,超级慢SELECT*FROM`order`ORDERBYidLIMIT100000,10;-- 优化写法:主键索引快速定位,再关联查询,无需扫描无效数据SELECTo.id,o.order_no,o.pay_priceFROM`order`oINNERJOIN(SELECTidFROM`order`ORDERBYidLIMIT100000,10)tempONo.id=temp.idORDERBYo.id;

六、业务层面优化(最高级、最有效)

很多慢SQL,SQL本身没问题,业务设计有问题。

6.1 大查询、统计、报表别查主库

主库只负责日常业务新增、修改、删除核心读写操作,压力必须稳住;统计报表、后台数据导出、历史大数据分析这类慢查询、大扫描SQL,全部迁移到从库执行,绝不碰主库,避免拖垮核心业务。

-- 烂写法:主库执行统计报表大SQL,扫描海量数据,压垮主库SELECTid,COUNT(*)ASorder_count,SUM(pay_price)AStotal_moneyFROM`order`GROUPBYuser_id;

优化操作:同样的统计SQL,代码里直接配置连接从库数据源执行,SQL不变,压力隔离,主库零影响。

6.2 热点数据、高频查询全部放Redis

首页数据、个人信息、配置参数、秒杀库存,不要每次查数据库。

高频访问、变动少的热点数据,提前缓存到Redis,接口查询优先读缓存,压根不执行SQL,从根源杜绝慢查询。

-- 烂写法:每次接口请求都查数据库,高频并发下数据库压力巨大SELECTid,username,phone,avatarFROM`user`WHEREid=1001;

优化操作:用户信息首次查询后存入Redis,后续请求直接读Redis,不再执行这条查询SQL,定时异步更新缓存数据即可。

6.3 大表一定要分库分表

单表数据量达到千万级别以上,不管怎么优化索引、改SQL写法,查询性能都会有物理瓶颈,读写压力天生扛不住,必须做分库分表,拆分大表为多个小表,从架构上解决慢查询问题。

-- 烂写法:上亿数据单表查询,再怎么加索引,范围查询、统计依旧慢SELECT*FROMbig_order_dataWHEREcreate_timeBETWEEN'2026-01-01'AND'2026-05-01';

优化操作:按时间或用户ID做分片分表,查询只路由到对应小分片表,扫描数据量骤减,SQL无需复杂优化自然变快。

七、生产慢SQL优化标准流程(照着这个步骤排查)

  1. 拿到慢SQL日志,找到执行时间最长、扫描行数最多的SQL;

  2. explain 分析执行计划,看是不是全表扫描;

  3. 检查是否缺索引,或者索引失效;

  4. 修改SQL写法,避免索引失效语法;

  5. 优化select字段、join、分页逻辑;

  6. 大查询迁移从库,热点数据加缓存;

  7. 超大表考虑分库分表。

八、最终总结一句话

慢SQL优化核心就三件事:别走全表扫描、索引别失效、数据库只干核心读写,别让它干统计和查询杂活。

http://www.jsqmd.com/news/747402/

相关文章:

  • 如何快速配置暗黑3技能连点器:D3KeyHelper完整使用指南
  • cube-composer社区贡献指南:如何提交你的创意关卡
  • 终极指南:如何免费解锁Cursor Pro功能并突破设备限制
  • test0202
  • 程序员必备的10个最佳网站中文版:终极学习与成长指南
  • 简易贪吃蛇
  • Windows平台APK安装解决方案:无缝运行Android应用的核心技术与实践指南
  • MetaMask扩展性能优化终极指南:快速解决插件加载缓慢问题
  • 【优化求解】基于ADMM求解插电式混合动力汽车凸优化能源管理问题附matlab代码
  • 揭秘AI系统提示词泄露:从DALL-E 3案例看用户行为分析的终极指南
  • 终极性能对决:ASP.NET Boilerplate 数据访问层 EF Core vs Dapper vs ADO.NET 谁更快?
  • Grist安全审计终极指南:10个关键步骤保护你的数据免受未授权访问
  • 岐金兰声明:佛学、心灵哲学与旧唯物主义的茧房
  • Ruler技能管理详解:扩展AI助手领域专业知识的终极方案
  • 别再只调阈值了!用OpenCV的Sobel梯度法,轻松应对低对比度图像缺陷检测难题
  • 别再死磕EMD和VMD了!试试这个2023年SCI顶刊新算法:特征模态分解(FMD)的Matlab保姆级教程
  • PKHeX自动化插件完整指南:如何轻松创建合法宝可梦
  • F - Plan Holidays
  • 告别Keepalived!在Windows Server上用自带NLB给Nginx做高可用,实测踩坑记录
  • hcxdumptool完整教程:从零开始掌握无线安全测试
  • EasyWeChat日志聚合分析终极指南:使用Kibana深度洞察微信API调用模式
  • TensorFlow图卷积网络终极指南:自定义损失函数与评估指标完全教程
  • 如何将Theatre动画导出为AVIF:下一代图像格式的完整指南
  • 终极Gin-Admin安全配置指南:JWT认证与RBAC权限的完美组合
  • AI提示词行业标准制定终极指南:从泄露系统提示词到规范化发展
  • 终极指南:如何用crypto-js实现GDPR、HIPAA等数据保护法规合规要求
  • 终极指南:如何利用Python构建专业的空气质量与水质监测系统
  • uni-app 初入门
  • DevilutionX崩溃恢复终极指南:快速解决游戏异常的10个实用技巧
  • Manim CE v.. 发布:动画构建更丝滑,随机性终于“可控”了!