mysql查询慢是数据库使用中常见的性能问题,排查这类问题需要从多个维度逐步定位根因,再采取对应的优化措施,以下是完整的排查流程和方法。

开启慢查询日志定位慢SQL
慢查询日志是mysql提供的用于记录执行时间超过指定阈值的SQL语句的功能,开启后可以直接获取需要优化的目标SQL。
首先查看当前慢查询相关的配置:
-- 查看慢查询是否开启 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'; -- 设置慢查询时间阈值为1秒,执行时间超过1秒的SQL会被记录 SET GLOBAL long_query_time = 1; -- 记录未使用索引的查询 SET GLOBAL log_queries_not_using_indexes = 'ON';
配置完成后,执行时间超过阈值的SQL会被记录到指定的日志文件中,直接查看日志文件就能获取需要优化的慢SQL列表。
使用EXPLAIN分析查询执行计划
拿到慢SQL后,需要使用EXPLAIN关键字分析SQL的执行计划,了解mysql是如何执行这条查询的,从而找到性能瓶颈。
使用方式是在慢SQL前加上EXPLAIN关键字:
EXPLAIN SELECT * FROM user WHERE age > 18 AND city = '北京';
执行后会返回多个字段,重点关注以下几个字段:
- type:表示访问类型,性能从好到坏依次是system > const > eq_ref > ref > range > index > ALL,出现ALL表示全表扫描,需要优化
- key:表示实际使用的索引,如果为NULL说明没有使用索引
- rows:表示mysql预估需要扫描的行数,数值越大性能越差
- Extra:额外信息,出现Using filesort、Using temporary表示需要额外排序或创建临时表,性能较差
检查索引使用情况
索引缺失或使用不当是查询慢的常见原因,需要结合执行计划检查索引是否合理。
索引缺失的排查
如果执行计划中key字段为NULL,且type为ALL,说明查询没有使用索引,需要根据查询条件创建合适的索引。比如上面的查询条件包含age和city,可以创建联合索引:
-- 创建联合索引,注意字段顺序要符合最左前缀原则 CREATE INDEX idx_age_city ON user(age, city);
索引失效的常见场景
即使创建了索引,也可能因为查询写法导致索引失效,常见场景如下:
- 对索引字段使用函数或运算,比如
WHERE YEAR(create_time) = 2023 - 使用
LIKE以通配符开头,比如WHERE name LIKE '%明' - 查询条件中使用
OR,且其中一个字段没有索引 - 字符串类型字段查询时没有加引号,导致隐式类型转换
排查其他性能影响因素
除了索引问题,还有以下因素可能导致查询慢:
锁竞争问题
如果查询涉及写操作相关的锁等待,会导致查询阻塞变慢。可以查看当前数据库的锁等待情况:
-- 查看当前运行的所有线程 SHOW PROCESSLIST; -- 查看innodb引擎的锁等待信息 SELECT * FROM information_schema.INNODB_LOCKS; SELECT * FROM information_schema.INNODB_LOCK_WAITS;
数据库配置不合理
部分配置参数不合理也会影响查询性能,比如innodb_buffer_pool_size设置过小,导致频繁磁盘IO,可以适当调大该参数,让更多数据缓存在内存中。
查询语句本身不合理
比如查询返回不必要的字段,使用SELECT *代替具体字段,或者查询没有加合理的分页限制,返回大量数据导致传输和处理变慢,这类问题需要优化SQL写法,只查询需要的字段,合理添加分页条件。
优化后的验证
完成优化后,需要再次执行EXPLAIN分析执行计划,确认type提升、rows减少、key正确使用了索引,同时可以实际执行SQL,对比优化前后的执行时间,确认性能问题已经解决。