MySQL - 慢查询优化

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL - 慢查询优化

1. 慢查询定位

1.1 开启慢查询日志

查看 MySQL 数据库是否开启了慢查询日志和慢查询日志的存储位置的命令如下:

show variables like 'slow_query_log%';

通过如下命令开启慢查询日志:

set global slow_query_log = on;
set global slow_query_log_file = 'oak-slow.log';
set global log_queries_not_using_indexes = on;
set long_query_time = 10;
  • long_query_time:指定慢查询的阀值,单位秒。如果 SQL 执行时间超过阀值,就属于慢查询记录到日志文件中。
  • log_queries_not_using_indexes:表示会记录没有使用索引的查询 SQL。前提是 slow_query_log 的值为 ON,否则不会奏效。

1.2 查询慢查询日志

  1. 查看慢查询日志:

直接使用文本编辑器打开slow.log日志即可:

  • time:日志记录的时间
  • User@Host:执行的用户及主机
  • Query_time:执行的时间
  • Lock_time:锁表时间
  • Rows_sent:发送给请求方的记录数,结果数量
  • Rows_examined:语句扫描的记录条数
  • SET timestamp:语句执行的时间点
  • select…:执行的具体的SQL语句
  1. 使用 mysqldumpslow 查看

MySQL 提供了一个慢查询日志分析工具 mysqldumpslow,可以通过该工具分析慢查询日志

内容。

在 MySQL bin 目录下执行下面命令可以查看该使用格式:

perl mysqldumpslow.pl --help

运行如下命令查看慢查询日志信息:

perl mysqldumpslow.pl -t 5 -s at C:\ProgramData\MySQL\Data\OAK-slow.log

除了使用 mysqldumpslow 工具,也可以使用第三方分析工具,比如 pt-query-digest、

mysqlsla 等。

2. 慢查询优化

2.1 索引和慢查询

  1. 如何判断是否为慢查询?

MySQL 判断一条语句是否为慢查询语句,主要依据 SQL 语句的执行时间,它把当前语句的执行时间跟 long_query_time 参数做比较,如果语句的执行时间 > long_query_time,就会把这条执行语句记录到慢查询日志里面。long_query_time 参数的默认值是 10s,该参数值可以根据自己的业务需要进行调整。

  1. 如何判断是否应用了索引?

SQL 语句是否使用了索引,可根据 SQL 语句执行过程中有没有用到表的索引,可通过 explain 命令分析查看,检查结果中的 key 值,是否为NULL。

  1. 应用了索引是否一定快?

下面我们来看看下面语句的 explain 的结果,你觉得这条语句有用上索引吗?比如:

select * from user where id > 0;

虽然使用了索引,但是还是从主键索引的最左边的叶节点开始向右扫描整个索引树,进行了全表扫描,此时索引就失去了意义。

而像 select * from user where id = 2; 这样的语句,才是我们平时说的使用了索引。它表示的意思是,我们使用了索引的快速搜索功能,并且有效地减少了扫描行数。

查询是否使用索引,只是表示一个 SQL 语句的执行过程;而是否为慢查询,是由它执行的时间决定的,也就是说是否使用了索引和是否是慢查询两者之间没有必然的联系。

我们在使用索引时,不要只关注是否起作用,应该关心索引是否减少了查询扫描的数据行数,如果扫描行数减少了,效率才会得到提升。对于一个大表,不止要创建索引,还要考虑索引过滤性,过滤性好,执行速度才会快。

2.2 提高索引过滤性

假如有一个5000万记录的用户表,通过 sex = ‘男’ 索引过滤后,还需要定位3000万,SQL 执行速度也不会很快。其实这个问题涉及到索引的过滤性,比如1万条记录利用索引过滤后定位10条、100条、1000条,那他们过滤性是不同的。索引过滤性与索引字段、表的数据量、表设计结构都有关系。

下面我们看一个案例:

-- 建表
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(32) NOT NULL DEFAULT '' COMMENT '名称',
  `sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 1:男 2:女',
  `age` int(11) NOT NULL COMMENT '年龄',
  PRIMARY KEY (`id`),
  KEY `idx_name_age_sex` (`name`,`age`,`sex`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
-- 插入数据
INSERT INTO `meta_demo`.`user` (`id`, `name`, `sex`, `age`) VALUES (1, 'javaboy001', 1, 18);
INSERT INTO `meta_demo`.`user` (`id`, `name`, `sex`, `age`) VALUES (1, 'javaboy002', 2, 18);
-- 查询语句 - 全表扫描
select * from user where age=18 and name like 'javaboy%';

优化1:

-- 添加索引
alter table user add index idx_name (name);

优化2:

-- 添加联合索引
alter table user add index idx_age_name (age, name);

优化3:

可以看到,index condition pushdown 优化的效果还是很不错的。再进一步优化,我们可以把名字的第一个字和年龄做一个联合索引,这里可以使用 MySQL 5.7 引入的虚拟列来实现。

-- 为user表添加first_name虚拟列,以及联合索引(first_name,age) 
alter table user add first_name varchar(2) generated always as (left(name, 1)), add index idx_fname_age (first_name, age); 
-- 分析 select
explain select * from user where first_name='张' and age=18;

2.3 慢查询原因总结

  1. 全表扫描: explain 分析 type 属性 all
  2. 全索引扫描: explain 分析 type 属性 index
  3. 索引过滤性不好: 靠索引字段选型、数据量和状态、表设计
  4. 频繁的回表查询开销: 尽量少用 select *,使用覆盖索引

3. 分页查询优化

3.1 一般性分页

一般的分页查询使用简单的 limit 子句就可以实现。limit 格式如下:

SELECT * FROM table_name LIMIT [offset,] rows

第一个参数指定第一个返回记录行的偏移量,注意从0开始;

第二个参数指定返回记录行的最大数目;

如果只给定一个参数,它表示返回最大的记录行数目;

思考1:如果偏移量固定,返回记录量对执行时间有什么影响?

select * from user limit 10000,1; 
select * from user limit 10000,10; 
select * from user limit 10000,100; 
select * from user limit 10000,1000; 
select * from user limit 10000,10000;

结果:在查询记录时,返回记录量低于100条,查询时间基本没有变化,差距不大。随着查询记录量越大,所花费的时间也会越来越多。

思考2:如果查询偏移量变化,返回记录数固定对执行时间有什么影响?

select * from user limit 1,100; 
select * from user limit 10,100; 
select * from user limit 100,100; 
select * from user limit 1000,100; 
select * from user limit 10000,100;

结果:在查询记录时,如果查询记录量相同,偏移量超过100后就开始随着偏移量增大,查询时间急剧的增加。(这种分页查询机制,每次都会从数据库第一条记录开始扫描,越往后查询越慢,而且查询的数据越多,也会拖慢总查询速度。)

3.2 分页优化方案

第一步:利用覆盖索引优化

select * from user limit 10000,100; 
-- >
select id from user limit 10000,100;

第二步:利用子查询优化

select * from user limit 10000,100; 
-- >
select * from user where id >= (select id from user limit 10000, 1) limit 100;

原因:使用了 id 做主键比较(id >=),并且子查询使用了覆盖索引进行优化。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
8天前
|
SQL 关系型数据库 MySQL
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
MySQL慢查询优化、索引优化,是必知必备,大厂面试高频,本文深入详解,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
|
24天前
|
缓存 关系型数据库 MySQL
MySQL执行计划选择策略:揭秘查询优化的艺术
【10月更文挑战第15天】 在数据库性能优化中,选择最优的执行计划是提升查询效率的关键。MySQL作为一个强大的关系型数据库管理系统,提供了复杂的查询优化器来生成执行计划。本文将深入探讨如何选择合适的执行计划,以及为什么某些计划更优。
51 2
|
12天前
|
SQL 关系型数据库 MySQL
MySQL慢查询优化、索引优化、以及表等优化详解
本文详细介绍了MySQL优化方案,包括索引优化、SQL慢查询优化和数据库表优化,帮助提升数据库性能。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
MySQL慢查询优化、索引优化、以及表等优化详解
|
7天前
|
SQL 关系型数据库 MySQL
【赵渝强老师】MySQL的慢查询日志
MySQL的慢查询日志用于记录执行时间超过设定阈值的SQL语句,帮助数据库管理员识别并优化性能问题。通过`mysqldumpslow`工具可查看日志。本文介绍了如何检查、启用及配置慢查询日志,并通过实例演示了慢查询的记录与分析过程。
|
17天前
|
缓存 监控 关系型数据库
如何优化MySQL查询速度?
如何优化MySQL查询速度?【10月更文挑战第31天】
44 3
|
18天前
|
搜索推荐 关系型数据库 MySQL
mysql like查询优化
通过合理的索引设计、使用全文索引、优化查询结构以及考虑分片和分区表,可以显著提高MySQL中 `LIKE`查询的性能。针对不同的应用场景选择合适的优化策略,能够有效地提升数据库查询效率,减少查询时间。希望这些方法和技巧能帮助您优化MySQL数据库中的模糊查询。
70 4
|
19天前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
43 1
|
26天前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:百万级数据统计优化实践
【10月更文挑战第21天】 在处理大规模数据集时,传统的单体数据库解决方案往往力不从心。MySQL和Redis的组合提供了一种高效的解决方案,通过将数据库操作与高速缓存相结合,可以显著提升数据处理的性能。本文将分享一次实际的优化案例,探讨如何利用MySQL和Redis共同实现百万级数据统计的优化。
69 9
|
21天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
98 1
|
26天前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
56 5