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 排查
  • 数据库设计时就考虑查询结构
相关推荐
-SGlow-1 小时前
MySQL相关概念和易错知识点(3)(表内容的CURD、内置函数)
linux·运维·服务器·数据库·mysql
飞翔的佩奇1 小时前
基于SpringBoot+MyBatis+MySQL+VUE实现的经方药食两用服务平台管理系统(附源码+数据库+毕业论文+部署教程+配套软件)
数据库·vue.js·spring boot·mysql·毕业设计·mybatis·经方药食两用平台
bing_1582 小时前
在多租户或多服务共享 Redis 时,如何做逻辑隔离或权限控制?
数据库·redis·缓存
ChaITSimpleLove3 小时前
PostgreSQL 中删除指定数据库下的所有表结构
数据库·postgresql·bash·sql 脚本·.net npgsql
孫治AllenSun4 小时前
【Mysql】字段隐式转换对where条件和join关联条件的影响
数据库·mysql·oracle
数据狐(DataFox)4 小时前
CTE公用表表达式的可读性与性能优化
经验分享·python·sql
生涯にわたる学び5 小时前
数据库02 网页html01 day44
数据库·html
Doris_LMS5 小时前
保姆级别IDEA关联数据库方式、在IDEA中进行数据库的可视化操作(包含图解过程)
java·mysql·postgresql
2301_793086876 小时前
Mysql group by
数据库·mysql
jllllyuz6 小时前
Spring中的事务是如何实现的
数据库·sql·spring