开发者

Java慢查询排查与性能调优完整实战指南

目录
  • 1. 事故全景:从告警到定位
    • 1.1 事故时间线
    • 1.2 关键指标异常
    • 1.3 排查工具链
  • 2. 深度剖析:mysql 分页查询的致命陷阱
    • 2.1 Offset 分页的执行原理
    • 2.2 索引失效的根本原因
    • 2.3 深度优化方案对比
      • 方案一:游标分页(推荐)
      • 方案二:覆盖索引优化
      • 方案对比表
  • 3. 完整优化实战
    • 3.1 MyBATjsis 改造示例
      • 3.2 服务层改造
      • 4. 防御体系:慢查询防控全景方案
        • 4.1 事前预防
          • 4.2 事中监控
          • 5. 优化效果验证
            • 5.1 压测数据对比
            • 6. 工程师的自我修养
              • 6.1 SQL 编写军规
              • 总结

                1. 事故全景:从告警到定位

                1.1 事故时间线

                timeline
                    title 故障时间轴
                    00:00 : 监控系统首次告警
                    00:05 : 数据库连接池使用率突破90%
                    00:08 : 网关开始出现503错误
                    00:12 : 自动扩容触发
                    00:15 : 人工介入排查

                1.2 关键指标异常

                指标正常值故障值超出阈值
                接口P99响应时间200ms
                数据库QPS8003500
                活跃连接数20200(max)10x

                1.3 排查工具链

                // 监控工具清单
                public class TroubleshootingTools {
                    String[] tools = {
                        "SkyWalking 8.7.0", 
                        "Arthas 3.6.7",
                        "Prometheus + Grafana",
                        "MySQL Slow Query Log"
                    };
                }
                

                2. 深度剖析:MySQL 分页查询的致命陷阱

                2.1 Offs编程客栈et 分页的执行原理

                Java慢查询排查与性能调优完整实战指南

                ​​性能消耗公式​​

                总成本 = 全表扫描成本 + 排序成本 + 跳过行成本

                2.2 索引失效的根本原因

                -- 问题SQL示例
                EXPLAIN SELECT * FROM member_info 
                WHERE status = 1 
                ORDER BY create_time DESC 
                LIMIT 10000, 20;
                

                ​​执行计划关键解读​​:

                • type: ALL:全表扫描
                • rows: 1250000:扫描行数
                • Extra: Using filesort:无法利用索引排序

                2.3 深度优化方案对比

                方案一:游标分页(推荐)

                -- 优化后SQL(基于ID分页)
                SELECT * FROM member_info 
                WHERE status = 1 AND id > #{lAVrmhXufastId}
                ORDER BY id ASC 
                LIMIT 20;
                

                方案二:覆盖索引优化

                -- 新增复合索引
                ALTER TABLE member_info 
                ADD INDEX idx_status_createtime (status, create_time);
                
                -- 改写SQL
                SELECT * FROM member_info 
                WHERE status = 1 
                ORDER BY create_time DESpythonC 
                LIMIT 20;
                

                方案对比表

                方案扫描行数排序方式适用场景
                原始Offset10020文件排序小数据量
                游标分页20索引排序大数据量、深度分页
                覆盖索引20索引覆盖中等数据量

                3. 完整优化实战

                3.1 MyBatis 改造示例

                public interface MemberMapper {
                    // 旧方法(问题代码)
                    @Select("SELECT * FROM member_info WHERE status = #{status} LIMIT #{offset}, #{limit}")
                    List<Member> listByPage(@Param("status") int status, 
                         编程客栈                 @Param("offset") int offset,
                                          @Param("limit") int limit);
                
                    // 新方法(优化后)
                    @Select("SELECT * FROM member_info WHERE status = #{status} AND id > #{lastId} ORDER BY id ASC LIMIT #{limit}")
                    List<Member> listByCursor(@Param("status") int status,
                                            @Param("lastId") long lastId,
                                            @Param("limit") int limit);
                }
                

                3.2 服务层改造

                public PageResult<Member> getMemberList(int pageSize, Long lastId) {
                    // 游标分页查询
                    List<Member> members = memberMapper.listByCursor(1, lastId, pageSize);
                    
                    // 获取下一页的游标
                    Long nextLastId = members.isEmpty() ? null : members.get(members.size()-1).getId();
                    
                    return new PageResult<>(members, nextLastId);
                }
                

                4. 防御体系:慢查询防控全景方案

                4.1 事前预防

                Java慢查询排查与性能调优完整实战指南

                4.2 事中监控

                # my.cnf 慢查询配置
                slow_query_log = 1
                slow_query_log_file = /var/log/mysql/mysql-slow.log
                long_query_time = 1
                log_queries_not_using_indexes = 1
                

                5. 优化效果验证

                5.1 压测数据对比

                场景TPS平均响应时间错误率CPU使用率
                优化前856100ms32%96%
                优化后2150230ms0%45%

                6. 工程师的自我修养

                6.1 SQL 编写军规

                1. ​​禁止​​ 无限制的 SELECT * ​​
                2. 必须​​ 为分页查询添加 ORDER BY ​​
                3. 推荐​​ 使用游标替代 OFFSET
                4. ​​强制​​ 为 WHERE 条件字段建立索引

                总结

                到此这篇关于Java慢查询排查与性能调优的文章就介绍到这了,更多相关Java慢查询排查与性能调优内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

                0

                上一篇:

                下一篇:

                精彩评论

                暂无评论...
                验证码 换一张
                取 消

                最新开发

                开发排行榜