您的当前位置:首页 >应用开发 >如何“医治”一条慢SQL? 正文
时间:2025-11-05 11:50:33 来源:网络整理编辑:应用开发
前言"苏工,订单列表又崩了!"接到电话时,我对着监控大屏上999ms的SQL响应时间哭笑不得。几年来,我发现一个定律:所有SQL问题都是在凌晨三点爆发!今天抽丝剥茧,教你用架构师的思维给慢SQL开刀手
"苏工,医治订单列表又崩了!何条"
接到电话时,医治我对着监控大屏上999ms的何条SQL响应时间哭笑不得。

几年来,医治我发现一个定律:所有SQL问题都是何条在凌晨三点爆发!
今天抽丝剥茧,医治教你用架构师的何条思维给慢SQL开刀手术。
希望对你会有所帮助。医治
使用EXPLAIN查看SQL语句的何条执行计划,相当于给SQL拍了张X光。医治
下面是何条一个典型的SQL问题,它是医治某电商平台历史订单查询的SQL语句:
复制SELECT * FROM orders o LEFTJOINusers u ON o.user_id = u.id LEFTJOIN products p ON o.product_id = p.id WHERE o.create_time > 2023-01-01 AND u.vip_level > 3 AND p.category_id IN (5,8) ORDERBY o.amount DESC LIMIT1000,20;1.2.3.4.5.6.7.8.9.使用EXPLAIN关键字查看执行计划的结果如下:
复制+----+-------------+-------+------+---------------+------+---------+------+---------+---------------------------------+ | id | select_type | table | type | possible_keys | key | rows | Extra| key_len | +----+-------------+-------+------+---------------+------+---------+------+---------+---------------------------------+ | 1 | SIMPLE | o | ALL | idx_user_time | NULL | 1987400 | Using where; Using filesort | | 1 | SIMPLE | u | ALL | PRIMARY | NULL | 100000 | Using where | | 1 | SIMPLE | p | ALL | PRIMARY | NULL | 50000 | Using where | +----+-------------+-------+------+---------------+------+---------+------+---------+---------------------------------+1.2.3.4.5.6.7.诊断报告:
全表扫描三连击(type=ALL)filesort暴力排序(内存警告)索引全军覆没如果通过执行计划查到是站群服务器索引有问题,我们就需要单独优化索引。何条
病根:JSON字段索引失效
错误用法:
复制ALTER TABLE users ADD INDEX idx_extend ((extend_info->$.is_vip));1.extend_info字段是医治JSON类型的字段,即使创建了索引,索引也会丢失。
正解姿势(MySQL 8.0+):
复制ALTER TABLE users ADD INDEX idx_vip_level (vip_level); ALTER TABLE orders ADD INDEX idx_create_user (create_time, user_id) COMMENT 组合索引覆盖查询;1.2.创建组合索引覆盖查询。
2.2 血管疏通术卡点分析:
原始join顺序是:
复制orders → users → products1.优化后的方案:
复制(子查询过滤users) → products → orders1.调整执行顺序,用小表驱动大表。
重写后的SQL:
复制SELECT o.* FROM products p INNERJOIN ( SELECT o.id, o.amount, o.create_time FROM orders o WHERE o.create_time > 2023-01-01 ) o ON p.id = o.product_id INNERJOIN ( SELECTid FROMusers WHERE vip_level > 3 ) u ON o.user_id = u.id WHERE p.category_id IN (5,8) ORDERBY o.amount DESC LIMIT1000,20;1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.术后效果:
先扫小表(users过滤后只有100条)消除冗余字段传输减少Join时临时表生成2.3 开颅手术通过执行计划锁定了问题,走错索引了,该怎么处理呢?
可以通过FORCE INDEX强制指定索引:
复制SELECT /*+ INDEX(o idx_create_user) */ o.id, o.amount FROM orders o FORCE INDEX (idx_create_user) WHERE o.create_time > 2023-01-01;1.2.3.4.使用衍生表加速:
复制SELECT * FROM ( SELECTid, amount FROM orders WHERE create_time > 2023-01-01 ORDERBY amount DESC LIMIT1020 ) tmp ORDERBY amount DESC LIMIT1000,20;1.2.3.4.5.6.7.8.9.10.医嘱:
警惕OR导致的索引失效用覆盖索引避免回表查询CTE表达式谨慎使用2.4 生命体征监测查看索引使用:
复制SHOW INDEX FROM orders;1.监控索引使用率:
复制SELECT object_schema, object_name, index_name, count_read, count_fetch FROM performance_schema.table_io_waits_summary_by_index_usage WHERE index_name IS NOT NULL;1.2.3.4.需要制定优秀的代码规范,否则可能会出现全表扫描的问题。
在日常工作中,免费源码下载我们要尽可能减少Java代码感染源。
MyBatis危险写法:
复制@Select("SELECT * FROM orders WHERE #{condition}") List<Order> findByCondition(@Param("condition") String condition);1.2.condition参数可以传入任何内容,如何传入了1=1,可能会导致查询所有的数据,走全表扫描,让查询效率变得非常低。
正确做法(参数化查询):
复制@Select("SELECT * FROM orders WHERE create_time > #{time}") List<Order> findByTime(@Param("time") Date time);1.2.消毒方案:
SQL审核平台接入(如Yearning)MyBatis拦截器拦截全表更新自动化EXPLAIN分析流水线3.2 查杀大表癌症如果遇到大表的癌症病例,可以用分库分表的方案解决。
病历案例:3亿订单表终极解决方案
复制// Sharding-JDBC分片配置 spring.shardingsphere.rules.sharding.tables.orders.actual-data-nodes=ds$0..1.orders_$->{2020..2023} spring.shardingsphere.rules.sharding.tables.orders.table-strategy.standard.sharding-column=create_time spring.shardingsphere.rules.sharding.tables.orders.table-strategy.standard.sharding-algorithm-name=time_range1.2.3.4.化疗方案:
时间维度分片(2020~2023年度表)用户ID取模分库冷热分离(OSS归档历史数据)优化三板斧:
定位:慢查询日志+执行计划分析切割:化繁为简拆分多步执行重建:符合业务场景的数据结构避坑口诀:
索引不是银弹,覆盖才是王道Join水深,能拆就拆Order By+Limit≠分页优化最后送上苏三的传秘方:当你优化SQL到怀疑人生时,不妨试试这三味药:
删业务逻辑加缓存换数据库保证药到病除(老板打不打死你我就不管了,哈哈哈)!
b2b信息网华为笔记本win10安装教程(详解华为笔记本win10系统安装步骤)2025-11-05 11:49
三星电脑硬盘装系统教程(从零开始,轻松安装操作系统的方法)2025-11-05 11:40
新机Win7系统安装教程——轻松安装你的操作系统2025-11-05 11:37
电脑安装CAD后致命错误的解决方法(如何应对CAD安装后出现的致命错误)2025-11-05 10:59
大白菜win7启动教程详解(轻松学会大白菜win7的正确启动方法)2025-11-05 10:33
用大白菜U盘制作XP系统的详细教程(简单步骤教你如何利用大白菜U盘制作XP系统安装盘)2025-11-05 10:11
Win7U盘重新系统教程(简明易懂的Win7U盘重新系统方法及步骤)2025-11-05 10:08
联想Miix5(探索Miix5在游戏体验上的表现如何)2025-11-05 10:04
使用OTG连接优盘安装系统的简易教程(通过OTG连接手机和优盘,轻松实现系统安装)2025-11-05 09:50
Lenovo100S评测(一款轻薄本打破常规,满足日常办公需求)2025-11-05 11:42
Mac系统重装教程(详解Mac系统重装步骤,让您的电脑焕然一新)2025-11-05 11:35
大白菜光盘制作教程(光盘制作技巧详解,让你的电脑焕发新生)2025-11-05 11:13
华硕Z490硬件安装教程(详解华硕Z490主板的安装步骤和注意事项)2025-11-05 10:57
利用U盘修复系统教程(一键修复,快速恢复系统正常运行)2025-11-05 10:46
以PE装GHO系统教程(利用PE工具制作GHO镜像,实现高效快捷的系统备份与恢复)2025-11-05 10:41
黑云重装win7系统教程(一键解决电脑卡顿,让您的Win7系统重现快速流畅体验)2025-11-05 10:33
三星Q430笔记本电脑的性能与使用体验(探索三星Q430笔记本电脑的优势和不足)2025-11-05 10:24
魅蓝2红米2电信版如何?(用一台手机满足所有需求,)2025-11-05 09:46