MySQL:SQL 慢查询优化的技术指南

1、简述

在 Java 后端开发中,数据库是系统性能瓶颈的高发地带,而 慢 SQL 查询 往往是系统响应迟缓的"罪魁祸首"。本文将全面梳理慢 SQL 的优化思路,并结合 Java 示例进行实战演练。


2、慢查询的常见表现

慢查询通常表现为:

  • 接口响应时间缓慢
  • 数据库 CPU 占用高
  • 表锁、死锁频繁
  • Java 应用线程池阻塞严重

慢 SQL 的主要成因

成因类型 说明
未使用索引 全表扫描,查询耗时
使用了低效的函数或表达式 LIKE '%xx%', DATE()
多表关联不当 join 条件缺失或不走索引
过多返回字段 只用到了部分字段却 SELECT *
where 条件不精准 无法过滤大量无关数据
数据库设计不合理 字段冗余、缺乏范式、字段类型错误等

3、慢查询优化的通用思路

✅ 加索引(重点)

  • WHEREJOINORDER BYGROUP BY 中涉及的字段加索引
  • 避免使用函数包裹字段,如 LEFT(name, 3),会导致无法使用索引

✅ 使用 EXPLAIN 分析执行计划

sql 复制代码
EXPLAIN SELECT * FROM orders WHERE user_id = 100;

关注字段:

字段 说明
type 连接类型(越接近 const 越好)
rows 扫描行数(越小越好)
key 使用的索引名称
Extra 是否使用临时表、排序等

✅ 分页优化

避免深度分页:

sql 复制代码
-- 慢查询(跳过大量行)
SELECT * FROM orders LIMIT 1000000, 20;

-- 推荐(使用上次主键记录)
SELECT * FROM orders WHERE id > 1000000 LIMIT 20;

✅ 拆表分区

  • 垂直拆分:将大表按字段拆分为多个表
  • 水平分表:按业务字段分库分表(如 user_id 分表)
  • 分区表:MySQL 原生支持(适合历史归档数据)

✅ 减少嵌套子查询

使用 JOIN 或临时表替代子查询,更高效。

✅ SQL 只查需要的字段

sql 复制代码
-- 慎用
SELECT * FROM user;

-- 推荐
SELECT id, name, email FROM user;

4、慢 SQL 实践排查与优化

✅ 示例:慢查询前后对比

原始 SQL(慢)
sql 复制代码
SELECT * FROM orders WHERE DATE(create_time) = '2024-01-01';

📉 问题:

  • 使用了 DATE() 函数,索引失效
  • 全表扫描,耗时严重
优化 SQL(快)
sql 复制代码
SELECT * FROM orders 
WHERE create_time >= '2024-01-01 00:00:00' 
  AND create_time < '2024-01-02 00:00:00';

📈 优点:

  • 范围查询走索引
  • 支持时间范围过滤

✅ Java 中日志配置监控慢 SQL

yaml 复制代码
# application.yml 示例(Spring Boot)
logging:
  level:
    com.zaxxer.hikari.HikariConfig: DEBUG
    com.zaxxer.hikari: TRACE
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo
    username: root
    password: root
    hikari:
      maximum-pool-size: 10
      connection-timeout: 3000

使用工具(如 p6spy)打印 SQL 及耗时,或开启 MySQL 慢查询日志:

sql 复制代码
-- MySQL 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 超过 1 秒记录

✅ SQL 优化 checklist

  • 是否使用了合适的索引
  • 是否避免了函数、表达式阻碍索引
  • 是否使用了 EXPLAIN 检查执行计划
  • 是否合理分页、避免深度翻页
  • 是否控制了查询字段数量
  • 是否考虑拆分大表或分区表
  • 是否避免了嵌套子查询

5、SQL 优化实战样例

场景 1:模糊查询优化

sql 复制代码
-- 慢:前置通配符无法使用索引
SELECT * FROM user WHERE name LIKE '%abc%';

-- 优化:使用全文索引或右模糊匹配
SELECT * FROM user WHERE name LIKE 'abc%';

场景 2:避免函数阻碍索引

sql 复制代码
-- 慢
SELECT * FROM orders WHERE YEAR(create_time) = 2024;

-- 快
SELECT * FROM orders 
WHERE create_time >= '2024-01-01' 
  AND create_time < '2025-01-01';

场景 3:多字段组合索引使用顺序

sql 复制代码
-- 有联合索引 (user_id, status)

-- 推荐:user_id 和 status 都参与
SELECT * FROM orders WHERE user_id = 100 AND status = 'PAID';

-- 不推荐:只用 status,索引无法生效
SELECT * FROM orders WHERE status = 'PAID';

6、结语

慢查询是系统性能优化的重要战场。对于 Java 开发者而言,理解 SQL 执行机制和优化原则,比"用缓存"更根本、更有效

日常开发中,应做到:

  • 编写 SQL 前先考虑是否能走索引
  • 查询慢时第一时间用 EXPLAIN 排查
  • 数据库设计时就考虑查询结构
相关推荐
松涛和鸣10 小时前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa10 小时前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k11 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦11 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL12 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·12 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
野生技术架构师12 小时前
SQL语句性能优化分析及解决方案
android·sql·性能优化
IT邦德12 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫12 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写