mysql如何分析sql执行效率和进行效率优化

【0】如何分析mysql中sql执行较慢的问题

  • 步骤1、观察,至少跑一天,看看生产的慢sql情况;
  • 步骤2、开启慢查询日志,设置阈值,比如超过5秒钟就是慢sql, 并将它抓取出来;
  • 步骤3、explain+慢sql分析;
  • 步骤4、show profile;(推荐)
  • 步骤5、运维经理或dba,进行sql数据库服务器的参数调优;(不推荐)

【总结】 

  • 总结1、慢查询的开启并捕获;
  • 总结2、explain + 慢sql分析;
  • 总结3、show profile 查询sql在mysql 服务器里面的执行细节和声明周期情况;
  • 总结4、sql数据库服务器的参数调优;

==============================================================================================

【1】exists + order by + group by 优化 

1.1、查询优化:使用 explain 查看执行计划,看是否可以基于索引查询;

1.2、小表驱动大表:当两个表做连接操作时, 其实就是双层for循环, 小表驱动大表的意思是, 小表(小数据集的表)放在第1层循环,大表(大数据集的表)放在第2层循环;

【补充】关于exists 语法 与 in 的区别:

exists语法:把 where id in 换位 where  exists 即可;

select ... from tbl where exists (subquery);

exists语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果 true 或 false, 来决定主查询的数据结果是否保留;
关于exists的提示:

  • 提示1:exists(subquery) 只返回true或false, 因此子查询中的select * 也可以是 select 1 或其他, 官方说法是实际执行时会忽略 select 清单,因此没有区别;
  • 提示2:exists 子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担心效率问题,可以进行实际检验;
  • 提示3:exists 子查询往往也可以用条件表达式,其他子查询或join来替代,哪种方法最优需要具体问题具体分析;

exists用法荔枝(exists与in的区别):

-- exists 语法 
select * from emp_tbl a where exists (select 1 from dept_tbl b where b.dept_id = a.dept_id)
order by a.rcrd_id 
limit 10
;
-- in 语法
select * from emp_tbl a where a.dept_id in (select b.dept_id from dept_tbl b)
order by a.rcrd_id 
limit 10
;

mysql如何分析sql执行效率和进行效率优化_第1张图片

-- 执行计划18
explain  select * from emp_tbl a where exists (select 1 from dept_tbl b where b.dept_id = a.dept_id)
;
-- 执行计划19
explain select * from emp_tbl a where a.dept_id in (select b.dept_id from dept_tbl b)
;

mysql如何分析sql执行效率和进行效率优化_第2张图片

==============================================================================================

1.2、order by 关键字优化 
优化1、尽量使用index方式排序,避免使用 filesort方式;

-- 建表
drop table if exists birth_tbl;
create table birth_tbl (
    `rcrd_id` int(10) unsigned primary key auto_increment COMMENT '记录编号'
    , age int default 0 comment '年龄'
    , birth timestamp default current_timestamp comment '生日'
) engine=innodb default charset=utf8 comment '生日表'
;
-- 插入数据
insert into birth_tbl(age) values 
(floor(1+(rand()*100)))
, (floor(1+(rand()*100)))
, (floor(1+(rand()*100)))
, (floor(1+(rand()*100)))
, (floor(1+(rand()*100)))
;
-- 添加索引
alter table birth_tbl
add key `idx_age_birth`(`age`, `birth`)
; 

mysql如何分析sql执行效率和进行效率优化_第3张图片

-- 查看order by的执行计划是否使用了文件排序; 

-- 执行计划20  索引排序
explain select * from birth_tbl where age > 30 order by age
;
-- 执行计划21  索引排序
explain select * from birth_tbl where age > 30 order by age, birth
;
-- 执行计划22  文件排序
explain select * from birth_tbl where age > 30 order by birth
;
-- 执行计划23  文件排序
explain select * from birth_tbl where age > 30 order by birth, age
;
-- 执行计划24  文件排序
explain select * from birth_tbl order by birth
;
-- 执行计划25  文件排序
explain select * from birth_tbl where birth > '2018-01-01 00:00:00' order by birth
;
-- 执行计划26  索引排序
explain select * from birth_tbl where birth > '2018-01-01 00:00:00' order by age
;
-- 执行计划27  文件排序
explain select * from birth_tbl order by age asc, birth desc
;

mysql如何分析sql执行效率和进行效率优化_第4张图片

mysql如何分析sql执行效率和进行效率优化_第5张图片

mysql支持两种方式的排序: 文件排序filesort 和 index 索引排序, index排序的效率较高; 它指mysql 扫描索引本身完成排序,文件排序filesort 效率较低;

【补充】 order by 满足两个情况:会使用索引排序:

  • 情况1:order by 语句使用索引最左前列;
  • 情况2: 使用where子句与order by 子句条件组合满足索引最左前列;

优化2、尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀;

优化3、如果不在索引列上,文件排序filesort有两种算法: mysql需要启动双路排序或单路排序;

优化策略:

  • 策略1:增大 sort_buffer_size 参数设置;
  • 策略2:增大 max_length_for_sort_data 参数的设置;
  • 策略3:why ?
  • mysql如何分析sql执行效率和进行效率优化_第6张图片

【总结】order by 总结-为排序使用索引:

  • 总结1、mysql两种排序方式: 文件排序或扫描有序索引排序;
  • 总结2、mysql能为排序和查询使用相同的索引;
  • 总结3、具体执行计划:

key idx_a_b_c(a, b, c);

  • 总结3.1、order by 能使用索引最左前缀的有:
  • order by a;
    order by a, b;
    order by a, b, c;
    order by a desc, b desc, c desc;  -- (要么全部升序,要么全部降序)
  •  
  • 总结3.2、如果where 使用索引的最左前缀定义为常量, 则order by 能使用索引;
  • where a = const order by b, c;
    where a=const and b=const order by c;
    where a = const and b > const order by b, c;
  •  
  • 总结3.3、不能使用索引进行排序:
  • order by a asc, b desc, c desc;
    where g = const order by b, c;
    where a = const order by c;
    where a=const order by a, d -- d不是索引的一部分;
    where a in (...) order by b, c;

1.3、group by 关键字优化;(均和order by 一样)

  • (1)group by 实质是先排序后再分组,遵照索引建的最佳左前缀;
  • (2)当无法使用索引列,增大 max_length_for_sort_data 参数的设置+增大 sort_buffer_size 参数的设置;
  • (3)where高于 having, 能写在 where 限定的条件就不要去 having 限定了 ;

=============================================================================================

【2】慢查询日志

0、什么是慢查询sql:sql运行时间超过 long_query_time 的sql 将会被记录到 慢查询日志中;

  • 0.1)mysql的慢查询日志是mysql提供的一种日志记录, 它用来记录在mysql中响应时间超过阈值的语句,具体指运行时间超过 long_query_time 值的sql, 则会被记录到慢查询日志中;
  • 0.2)long_query_time 的默认值为10, 则表示运行时间超过10秒的sql语句被记录到慢查询日志中;
  • 0.3)通过收集超过10秒的sql, 结合之前 explain 进行全面分析;

1)mysql的慢查询日志

  • 1.1)默认情况下, mysql没有开启慢查询日志,需要手工开启;
  • 1.2)如果不是调优需要的话,一般不建议启动该参数; 因为开启慢查询日志或多或少会带来一定的性能影响。慢查询日志支持将日志记录写入文件;

2)查看是否开启慢查询日志以及如何开启? 
默认: show variables like '%slow_query_log%';

mysql如何分析sql执行效率和进行效率优化_第7张图片

开启: set global slow_query_log=1;

mysql如何分析sql执行效率和进行效率优化_第8张图片

【注意】

  • 注意1: 使用 set global slow_query_log=1 开启了慢查询日志只对当前数据库生效, 如果mysql重启以后则会失效;
  • 注意2:如果要永久生效,必须修改配置文件 my.cnf ;

  • mysql如何分析sql执行效率和进行效率优化_第9张图片

如何设置long_query_time ?
show variables like 'long_query_time%';
查询 long_query_time的值?即查询当前多少秒算慢?
show variables like 'long_query_time'

mysql如何分析sql执行效率和进行效率优化_第10张图片

设置慢的阈值时间? 
set global long_query_time=3;

mysql如何分析sql执行效率和进行效率优化_第11张图片

为什么设置后期 long_query_time 还是没变;
这个时候需要重新连接或新开一个会话; 或者执行 show global variables like 'long_query_time' ;

mysql如何分析sql执行效率和进行效率优化_第12张图片

如何制造 执行时间超过3秒的SQL?
如  select sleep(4);

mysql如何分析sql执行效率和进行效率优化_第13张图片

mysql如何分析sql执行效率和进行效率优化_第14张图片

查看当前有多少条慢查询sql?
show global status like '%slow_queries%';

mysql如何分析sql执行效率和进行效率优化_第15张图片

补充1:如何在my.ini文件中配置mysql的慢查询参数, 如下:mysql如何分析sql执行效率和进行效率优化_第16张图片
补充2: 日志分析工具 mysqldumpslow ,常用于在生产中分析sql的性能;

mysql如何分析sql执行效率和进行效率优化_第17张图片

mysql如何分析sql执行效率和进行效率优化_第18张图片

 

=============================================================================================
【3】、批量数据脚本;

-- 新建函数-产生随机的字符串
drop function if exists rand_str;
delimiter ##
create function rand_str(n int) returns varchar(255)
begin 
	declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	declare return_str varchar(255) default '';
	declare i int default 0;
	while i < n do 
		set return_str=concat(return_str, substring(chars_str, floor(1+rand()*52), 1));
		set i=i+1;
	end while;
	return return_str;
end ## 
delimiter ;

-- 新建函数-产生随机的整数
drop function if exists rand_num; 
delimiter ##
create function rand_num() returns int
begin 
	declare i int default 0;
	set i=floor(100+rand()*10);
	return i;
end ## 
delimiter ;

-- 创建存储过程,函数没法单独被调用,只能通过存储过程进行调用;
-- 新建存储过程-调用函数批量插入数据 
drop procedure if exists insert_emp; 
delimiter ##
create procedure insert_emp(in start_num int, in max_num int) 
begin 
	declare i int default 0;
	set autocommit=0;
	repeat 
		set i=i+1;
		INSERT INTO mybatis.emp_tbl (emp_id, dept_id, name)VALUES(rand_num(), rand_num(), rand_str(20));
		until i = max_num
	end repeat;
	commit;
end ## 
delimiter ;


call insert_emp(0, 100000)
;

=============================================================================================

【4】show profile

4、show profile
4.0)intro:
show profile 提供了比 explain 更加细粒度的sql执行计划分析和sql优化;
4.1)是什么: 是mysql提供可以用来分析当前回话中语句执行的资源消耗情况。可以用于sql的调优测量;
4.2)官网: https://dev.mysql.com/doc/refman/8.0/en/show-profile.html 
4.3)默认情况下,参数处于关闭状态,并保持最近15次的运行结果;
4.4)分析步骤:

  • 步骤1:是否支持,看看当前的mysql版本是否支持 show profile;
  • show variables like 'profiling';
  • mysql如何分析sql执行效率和进行效率优化_第19张图片
  • 步骤2:开启功能,默认是关闭,使用前需要开启;
  • 步骤3:运行 sql; 且要运行耗时长的sql;
  • select * from emp_tbl e inner join dept_tbl d on e.dept_id = d.dept_id
    ;
    select * from emp_tbl e left join dept_tbl d on e.dept_id = d.dept_id
    ;
    select * from emp_tbl group by rcrd_id%10 
    ; 
  • 步骤4:查看结果,show profiles;
  • 步骤5:诊断sql, show profile cpu, block io for query 上一步前面的问题sql数字号码; 查看一条sql的完整生命周期;  show profile cpu, block io for query 3; 
  • mysql如何分析sql执行效率和进行效率优化_第20张图片
  • 补充: 不仅仅可以查看 cpu, block io , 还可以查看如下类型的信息;
  • mysql如何分析sql执行效率和进行效率优化_第21张图片
  • 步骤6: 日常开发需要注意的结论;以下结论都是性能比较差的sql的表现形式,即 show profile cpu, block io for query 3; 中的status中出现以下4种中的一种或几种,则sql执行效率较差,需要优化; 

【关于show profile的结论】

  • 结论1)converting heap to myisam 查询结果太大, 内存都不够用了,往磁盘上搬;
  • 结论2)creating tmp table 创建临时表: 拷贝数据到临时表,用完再删除;mysql如何分析sql执行效率和进行效率优化_第22张图片
  • mysql如何分析sql执行效率和进行效率优化_第23张图片
  • 结论3)copying to tmp table on disk, 把内存中临时表复制到磁盘,危险
  • 结论4) locked :锁住;  
     

=============================================================================================

【5】、全局查询日志;
5.1、配置启用: 在mysql的 my.ini 中,配置如下:

#开启
general_log=1
#记录日志文件的路径
general_log_file=/path/logfile
#输出格式
log_output=FILE

5.2、编码启用:命令如下:

set global general_log=1;
set global log_output='TABLE';

mysql如何分析sql执行效率和进行效率优化_第24张图片
此后, 你所编写的sql语句, 将会记录到 mysql库里的general_log 表,可以用下面的命令查看:
select * from mysql.general_log; 

mysql如何分析sql执行效率和进行效率优化_第25张图片
5.3、建议不要在生产环境开启这个功能, 仅在测试环境开启以便调试;

 

【建议】 建议使用 show profile 功能分析和优化sql性能; 
 

 

你可能感兴趣的:(mysql如何分析sql执行效率和进行效率优化)