MySQL 慢查询定位与 SQL 性能优化实战教程

 更新时间:2025年12月17日 11:13:17   作者:五阿哥永琪  
本文介绍了如何定位和解决MySQL慢查询,首先,需要开启和检查慢查询日志,然后通过分析日志和使用`EXPLAIN`语句来定位问题,接着,文章讨论了基础优化、JOIN优化、子查询优化以及如何创建和使用索引,通过这些方法,可以有效提高MySQL的性能,感兴趣的朋友跟随小编一起看看吧

如何定位并解决慢查询?

1. 开启/检查慢日志

  • 看一下是否开启慢日志
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'slow_query_log_file';
  • 如果未开启,临时开启(生产环境建议永久配置):
SET GLOBAL slow_query_log = ON; 
SET GLOBAL long_query_time = 1;

2. 分析日志

mysqldumpslow(MySQL 自带)

# 按执行次数排序前10条
  mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
  # 按总耗时排序前10条
  mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

3. 用explain分析执行计划

在SQL前面加explain

EXPLAIN SELECT id, order_no 
FROM orders 
WHERE user_id = 100 AND create_time >= '2024-01-01' 
ORDER BY create_time DESC;
  • 重点查看四个字段
字段看什么
type是否出现 ALL(全表扫描)
rows扫描行数是否过大
key是否使用到了正确索引
Extra是否出现 Using filesortUsing temporary

SQL优化?

一、基础优化

1. 避免select *

-- ❌ 不推荐 
SELECT * FROM users; 
-- ✅ 推荐 
SELECT id, name, email FROM users;

2. 使用合适的where条件

  • 尽量在where中使用索引字段
  • 避免对字段进行函数操作或类型转换(导致索引失效)
-- ❌ 索引失效 
SELECT * 
FROM orders 
WHERE YEAR(create_time) = 2024; 
-- ✅ 使用范围查询,可走索引 
SELECT * 
FROM orders 
WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';

3. 合理使用索引

  • 对经常用于where、join、order by、group by的列建立索引
  • 比卖你过度索引(影响写入性能)
  • 考虑使用复合索引(最左前缀原则)

4. 避免全表扫描

通过explain检查是否使用了索引

EXPLAIN SELECT * FROM products WHERE category_id = 10;

二、JOIN优化(多表查询)

1. 大表驱动小表

  • 在MySQL中,通常将小结果姐放在left,大表在right

2. 确保JOIN字段都有索引

  • 两个表关联字段都应该有索引

3. 避免多层嵌套JOIN

  • 复杂JOIN可拆分为多个简单查询

三、子查询 vsJOIN

子查询在某些数据库中效率较低,可以尝试改成JOIN

-- ❌ 子查询(可能低效) 
SELECT * 
FROM users 
WHERE id IN (SELECT user_id FROM orders WHERE amount > 100); 
-- ✅ 改写为 
JOIN SELECT DISTINCT u.* 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE o.amount > 100;

分页优化

  • 深分页(如LIMIT 100000,20)性能查,因为要跳过大量的数据
    • 优化方案:
      • 使用游标分页(基于上一页最后一条记录的ID或时间):
​
SELECT * FROM messages 
WHERE id > 100000 
ORDER BY id 
LIMIT 20;
​

如何创建、使用索引?

索引介绍

索引类型说明
主键索引聚簇索引,数据按主键物理存储,每一张表只能一个
唯一索引不允许出现重复值
普通索引最基本的索引,允许重复和null
全文索引用于文本搜索
前缀索引对字符串类的前N个字段创建索引,节省空间
覆盖索引非独立类型,查询字段全部包含在索引中,无需回表

一、创建索引

1. 创建普通索引

-- 方法1:CREATE INDEX(推荐用于已有表) 
CREATE INDEX index_name ON table_name (column_name); 
-- 示例:在 users 表的 email 字段上创建索引 
CREATE INDEX idx_email ON users (email);

2. 创建唯一索引

CREATE UNIQUE INDEX idx_username ON users (username);

3. 创建复合索引

  • 符合索引使用时必须遵循最左前缀原则,查询时必须包含最左边的列才能生效
-- 按顺序:先按 category_id,再按 created_at 排序 
CREATE INDEX idx_category_created ON products (category_id, created_at);

4. 在建表时直接定义索引

CREATE TABLE orders (
	id BIGINT PRIMARY KEY AUTO_INCREMENT, 
	user_id INT NOT NULL, 
	status VARCHAR(20), 
	created_at DATETIME, 
	-- 主键自动创建聚簇索引(InnoDB) 
	INDEX idx_user_status (user_id, status), -- 普通复合索引 
	UNIQUE INDEX uk_order_no (order_no) -- 唯一索引 
	);

5. 添加主键(自动添加聚簇索引)

ALTER TABLE table_name ADD PRIMARY KEY (id);

到此这篇关于MySQL 慢查询定位与 SQL 性能优化实战指南的文章就介绍到这了,更多相关mysql慢查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mysql中url时区的陷阱该如何规避详解

    mysql中url时区的陷阱该如何规避详解

    最近在工作中发现一个问题,是关于mysql中url时区的,发现这个陷阱如果大家不注意可能都会遇到,所以给大家总结下,这篇文章主要给大家介绍了关于mysql中url时区的陷阱该如何规避的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • Mysql主从复制与读写分离图文详解

    Mysql主从复制与读写分离图文详解

    这篇文章主要给大家介绍了关于Mysql主从复制与读写分离的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 关于sql count(列名)、count(常量)、count(*)之间的区别

    关于sql count(列名)、count(常量)、count(*)之间的区别

    这篇文章主要介绍了关于sql count(列名)、count(常量)、count(*)之间的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • MySQL创建表操作命令分享

    MySQL创建表操作命令分享

    这篇文章主要介绍了MySQL创建表操作命令分享,分享内容有查看所有表,创建表和MySQL支持的常用数据类型,具有一的参考价值,需要的小伙伴可以参考一下
    2022-03-03
  • MySQL 常用函数实操攻略之从基础到实战案例

    MySQL 常用函数实操攻略之从基础到实战案例

    MySQL操作中,函数是提升数据处理效率的核心工具,无论是日期计算、字符串拼接,还是数据加密,掌握常用函数能让复杂需求变得简单,本文从实际出发,梳理日期、字符串、数学及高频函数的用法,每个函数都附带可直接运行的代码案例,帮你快速上手,感兴趣的朋友跟随小编一起看看吧
    2025-10-10
  • 深入解析半同步与异步的MySQL主从复制配置

    深入解析半同步与异步的MySQL主从复制配置

    这篇文章主要介绍了半同步与异步的MySQL主从复制配置,包括不同的连接方案的讨论,需要的朋友可以参考下
    2015-12-12
  • sql server自动编号的三种方法

    sql server自动编号的三种方法

    自增列是最简单和常见的方法,适用于大多数情况,本文介绍了SQL Server中三种常见的自动编号方法:自增列、序列和触发器,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • mysql 数据汇总与分组

    mysql 数据汇总与分组

    这篇文章主要介绍了mysql 数据汇总与分组,我们经常需要汇总数据而不用把它们实际检索出来,为此MySQL提供了专门的函数。使用这些函数,MySQL查询可用于检索数据,以便分析和报表生成。下面来看看具体例子,需要的朋友可以参考一下
    2021-10-10
  • 解决启动MongoDB错误:error while loading shared libraries: libstdc++.so.6:cannot open shared object file:

    解决启动MongoDB错误:error while loading shared libraries: libstdc+

    本文提供了解启动MongoDB时提示:error while loading shared libraries: libstdc++.so.6: cannot open shared object file: 错误的解决方案
    2018-10-10
  • 使用mysql_udf与curl库完成http_post通信模块示例

    使用mysql_udf与curl库完成http_post通信模块示例

    这篇文章主要介绍了使用mysql_udf与curl库完成http_post通信模块示例,需要的朋友可以参考下
    2014-03-03

最新评论