 
 前言"苏工,何优化条订单列表又崩了!何优化条" 接到电话时,何优化条我对着监控大屏上999ms的何优化条SQL响应时间哭笑不得。 几年来,何优化条我发现一个定律:所有SQL问题都是何优化条在凌晨三点爆发! 今天抽丝剥茧,何优化条教你用架构师的何优化条思维给慢SQL开刀手术。 希望对你会有所帮助。何优化条 1.术前检查:找准病灶(1)EXPLAIN 查看执行计划使用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暴力排序(内存警告)索引全军覆没        2.手术方案:精准打击(1)单表代谢手术如果通过执行计划查到是香港云服务器索引有问题,我们就需要单独优化索引。何优化条 病根: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时临时表生成        (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表达式谨慎使用        (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.                                            3.术后护理:体系化治理(1)SQL消毒中心需要制定优秀的代码规范,否则可能会出现全表扫描的问题。 在日常工作中,b2b供应网我们要尽可能减少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分析流水线        (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到怀疑人生时,不妨试试这三味药: 删业务逻辑加缓存换数据库        保证药到病除(老板打不打死你我就不管了,哈哈哈)! 服务器托管 |