本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了关于慢查询优化的相关问题,包括了利用慢查询日志定位慢查询sql、通过explain分析慢查询sql、修改sql尽量让sql走索引,下面一起来看一下,希望对大家有帮助。
推荐学习:mysql视频教程
1 慢查询优化思路当发生慢查询的时候,优化的思路为:
利用慢查询日志定位慢查询 sql
通过 explain 分析慢查询 sql
修改 sql,尽量让 sql 走索引
2 慢查询日志mysql 提供了一个功能——慢查询日志,会记录查询时间超过指定时间阈值的 sql 到日志中,便于我们定位慢查询并且优化对应的 sql 语句。
首先查看 mysql 中关于慢查询相关的全局变量:
mysql> show global variables like '%quer%';+----------------------------------------+-------------------------------+| variable_name | value |+----------------------------------------+-------------------------------+| binlog_rows_query_log_events | off || ft_query_expansion_limit | 20 || have_query_cache | yes || log_queries_not_using_indexes | off || log_throttle_queries_not_using_indexes | 0 |==========================================================================| long_query_time | 10.000000 |【1】慢查询的时间阈值==========================================================================| query_alloc_block_size | 8192 || query_cache_limit | 1048576 || query_cache_min_res_unit | 4096 || query_cache_size | 16777216 || query_cache_type | off || query_cache_wlock_invalidate | off || query_prealloc_size | 8192 |==========================================================================| slow_query_log | off |【2】慢查询日志是否开启| slow_query_log_file | /var/lib/mysql/linux-slow.log |【3】慢查询日志文件存储位置==========================================================================+----------------------------------------+-------------------------------+15 rows in set (0.00 sec)
这里主要关注三个变量:
long_query_time,慢查询的时间阈值,单位秒,如果一个 sql 语句的执行时间超过这个值,那么 mysql 就认定其为慢查询
slow_query_log,慢查询日志功能是否开启,默认关闭,开启后记录慢查询
slow_query_log_file,慢查询日志文件的存储位置
默认慢查询日志功能是关闭的,因此我们需要启动该功能
# 开启慢查询日志mysql> set global slow_query_log=on;query ok, 0 rows affected (0.00 sec)# 设置慢查询时间阈值mysql> set long_query_time=1;query ok, 0 rows affected (0.00 sec)
这样子设置后,mysql 重启会丢失这些配置,需要在配置文件中修改才会永久有效。
3 explain我们可以使用 explain 分析 sql 语句的执行情况,例如:
mysql> explain select sum(1+2);
执行结果如下,可以看到有很多字段
我们主要看看一些重要的字段:
select_type 表示查询语句的查询类型,包括简单查询、子查询等等
table 表示查询的表,不一定是存在表,可能是本次查询中得到的临时表
type 表示检索类型,使用全表扫描、还是索引扫描等
possible_keys表示可能使用的索引列
keys表示查询中实际使用的索引列,由查询优化器决定
3.1 select_type 字段
3.2 type 字段
对于 innodb 存储引擎,type列通常都是all或者index。
关于 type 字段的值,其从上到下对应的 sql 的执行性能逐渐变差。
3.3 extra 字段
4 慢查询例子准备数据,数据表结构:
create table user_info_large (`id` bigint unsigned not null auto_increment comment '主键',`account` varchar(20) not null comment '用户账号',`name` varchar(20) not null comment '用户名',`password` varchar(20) not null comment '用户密码',`area` varchar(20) not null comment '用户地址',`signature` varchar(50) not null comment '个性签名',primary key (`id`) comment '主键',unique (`account`) comment '唯一索引',key `index_area_signture` (`area`, `signature`) comment '组合索引');
随机生成 200w 条数据
mysql> select count(id) from user_info_large;+-----------+| count(id) |+-----------+| 2000000 |+-----------+1 row in set (0.38 sec)
截取部分数据:
执行以下 sql 语句,没有使用任何索引字段:
select name from user_info_large order by name desc limit 0,100000;
navicat 工具显示的查询时间如下,这并不是 mysql 真正执行 sql 的时间,这里面包含了网络传输等时间:
sql 具体的查询时间可以查看慢查询日志:
# time: 2022-09-26t13:44:18.405459z# user@host: root[root] @ [ip] id: 1893# query_time: 10.162999 lock_time: 0.000113 rows_sent: 100000 rows_examined: 2100000set timestamp=1664199858;select name from user_info_large order by name desc limit 0,100000;
关于其中一些信息的说明:
time:sql 执行的开始时间
query_time:sql 语句查询花费的时间,可以看到花费了 10 秒钟
lock_time:等待锁表的时间
rows_sent:语句返回的记录数
rows_examined:从存储引擎中返回的记录数
正在执行的慢查询是不会被记录到慢查询日志的,只有等待其执行完毕才会记录到日志中。
我们可以使用 show processlist 查看正在执行 sql 的线程。
再执行以下语句,使用索引 account 字段:
select account from user_info_large order by account desc limit 0,100000;
查看慢查询日志,并没有被记录下来。
现在分别使用 explain 查看 sql 语句的执行情况:
explain select name from user_info_large order by name desc limit 0,100000;
分析情况如下:
可以看到没有使用到索引,type 为 all 表示全表扫描,效率最差,并且 extra 也是外部排序。
再看看这条 sql 语句:
explain select account from user_info_large order by account desc limit 0,100000;
分析情况如下:
type 为 index,使用了索引,使用的索引字段为 account,extra 显示为使用索引排序。
因此,在实际开发中,我们可以针对慢查询的 sql,使用 explain 分析语句,根据分析情况以及索引的设计,重新设计 sql 语句,让 sql 语句尽量走索引,走合适的索引。
5 优化器与索引在执行 sql 时,mysql 的优化器会根据情况选择索引,但并不能保证其执行时间一定最短,我们可以根据实际情况使用 force key (index) 让 sql 语句强制走某个索引。
例如,以下语句执行后,key 字段为 account,并没有走主键索引。
explain select count(id) from user_info_large;
如果使用 force key,就可以强制令语句走主键索引。
explain select count(id) from user_info_large force key (primary);
6 总结在项目中如果发现部分 sql 语句执行缓慢,等待查询时间长,可以考虑优化慢查询,具体思路为:
通过慢查询日志定位 sql
使用 explain 分析 sql
修改 sql,令其走合适的索引
在使用 explain 时,我们主要关注这些字段:
type
key
extra
在编写 sql 使用索引的时候,我们尽量注意一下规则:
模糊查询不要使用通配符 % 开头,例如 like '%abc'
使用 or 关键字时,两边的字段都要有索引。或者使用 union 替代 or
使用复合索引遵循最左原则
索引字段不要参加表达式运算、函数运算
推荐学习:mysql视频教程
以上就是总结分享之mysql慢查询优化的思路的详细内容。