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
;
-- 执行计划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)
;
==============================================================================================
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`)
;
-- 查看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支持两种方式的排序: 文件排序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 ?
【总结】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%';
开启: set global slow_query_log=1;
【注意】
- 注意1: 使用 set global slow_query_log=1 开启了慢查询日志只对当前数据库生效, 如果mysql重启以后则会失效;
- 注意2:如果要永久生效,必须修改配置文件 my.cnf ;
如何设置long_query_time ?
show variables like 'long_query_time%';
查询 long_query_time的值?即查询当前多少秒算慢?
show variables like 'long_query_time'
设置慢的阈值时间?
set global long_query_time=3;
为什么设置后期 long_query_time 还是没变;
这个时候需要重新连接或新开一个会话; 或者执行 show global variables like 'long_query_time' ;
如何制造 执行时间超过3秒的SQL?
如 select sleep(4);
查看当前有多少条慢查询sql?
show global status like '%slow_queries%';
补充1:如何在my.ini文件中配置mysql的慢查询参数, 如下:
补充2: 日志分析工具 mysqldumpslow ,常用于在生产中分析sql的性能;
=============================================================================================
【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_numend 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';
- 步骤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;
- 补充: 不仅仅可以查看 cpu, block io , 还可以查看如下类型的信息;
- 步骤6: 日常开发需要注意的结论;以下结论都是性能比较差的sql的表现形式,即 show profile cpu, block io for query 3; 中的status中出现以下4种中的一种或几种,则sql执行效率较差,需要优化;
【关于show profile的结论】
- 结论1)converting heap to myisam 查询结果太大, 内存都不够用了,往磁盘上搬;
- 结论2)creating tmp table 创建临时表: 拷贝数据到临时表,用完再删除;
- 结论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';
此后, 你所编写的sql语句, 将会记录到 mysql库里的general_log 表,可以用下面的命令查看:
select * from mysql.general_log;
5.3、建议不要在生产环境开启这个功能, 仅在测试环境开启以便调试;
【建议】 建议使用 show profile 功能分析和优化sql性能;
mysql如何分析sql执行效率和进行效率优化相关推荐
- Mysql体系结构及sql执行过程总结
Mysql体系结构及sql执行过程总结 一.体系结构图 各模块说明: 1.Connectors:各应用程序与SQL的交互 2. Management Serveices & Utilities ...
- sql执行组件是灰色的_如何分析SQL执行计划图形组件
sql执行组件是灰色的 In the previous articles of this series, SQL Server Execution Plans overview and SQL Ser ...
- ClickHouse 使用EXPLAIN 分析 SQL 执行计划
1.1. 使用 EXPLAIN 分析 SQL 执行计划 本节介绍如何使用EXPLAIN命令分析SQL语句的执行计划. 1.1.1. EXPLAIN概述 执行计划是进行SQL查询调优的重要参考.在Cli ...
- 【ClickHouse SQL 极简教程】使用EXPLAIN 分析 SQL 执行计划
1.1. 使用 EXPLAIN 分析 SQL 执行计划 本节介绍如何使用EXPLAIN命令分析SQL语句的执行计划. 1.1.1. EXPLAIN概述 执行计划是进行SQL查询调优的重要参考.在Cli ...
- 优化SQL步骤——查看SQL执行频率 || 定位低效率执行SQL
优化SQL步骤 在应用的的开发过程中,由于初期数据量小,开发人员写 SQL 语句时更重视功能上的实现, 但是当应用系统正式上线后,随着生产数据量的急剧增长,很多 SQL 语句开始逐渐显露出性能问题,对 ...
- [06][03][01] MySQL架构与SQL执行流程
文章目录 1. 一条 SQL 语句执行步骤 1.1 通信 1.1.1 通信类型 1.1.2 连接方式 1.1.3 通信协议 1.1.4 通信方式 1.2 查询缓存 1.3 语法解析和预处理 (Pars ...
- Mysql 慢查询 Sql执行计划 SQL每阶段的耗时
文章目录 前言 一.慢查询的相关参数 slow_query_log 是否开启了慢查询 开启慢查询 slow_query_log_file 指定慢查询日志的存储路径及文件 long_query_time ...
- 数据库-优化-通过执行计划查询分析SQL执行计划-每个字段的说明
通过explain查询分析SQL的执行计划 1.使用explain查询SQL的执行计划 SQL的执行计划侧面反映出了SQL的执行效率,具体执行方式如下所示: 在执行的SQL前面加上explain关键词 ...
- MySQL 架构与 SQL 执行流程
使用的mysql是5.7版本 1. 一条查询 SQL 语句是如何执行的? 程序或者工具要操作数据库,第一步要跟数据库建立连接. 1.1. 通信协议 首先,MySQL 必须要运行一个服务,监听默认的端口 ...
最新文章
- 纪念:2006年我在51CTO的第一帖
- C#中抽象类和接口的区别与使用
- docker 删除所有镜像_关于 Docker 镜像的操作,看完这篇就够啦 !(下)| 文末福利...
- 【转载】使用Imaging组件加载GIF动画
- Java Web开发技术详解~Web的概念
- 最短路径——SPFA算法(蓝桥杯试题集)
- 雷林鹏分享:C# 事件(Event)
- 输出200以内所有素数(python)
- vscode json插件
- 【目标检测】|RFB ECCV2018
- Keychain-Dumper的安装,签名与使用
- windows下 利用CoreAudio,Libmad,和3D环绕音效原理实现的MP3播放器
- 985大学和二本计算机,985大学名单排名(二本)
- xcode 常见错误
- html 关闭当前tab页面,js关闭浏览器的tab页(兼容)
- c语言链表删除重复点,【图片】想问一道链表题,如何删除重复元素【c语言吧】_百度贴吧...
- pyscripter与python的关系_【已解决】PyScripter启动出错:Python could not be properly initialized. We must quit....
- Android电子牌外接USB读卡器读取内容模拟键盘事件
- kafka listeners 和 advertised.listeners 的区别及应用
- C#,图像二值化(05)——全局阈值的联高自适应算法(Legal Self-Adaptive Thresholding)及其源代码
热门文章
- Monster Hunter(2020南京M)
- H.Minimum-cost Flow
- 【每日一题】8月17日题目精讲-[SCOI2009]生日礼物
- [2021 CSP-S提高组] 题解(廊桥分配+括号序列+回文+交通规划)
- 【CF1179 A,B,C】Valeriy and Deque / Tolik and His Uncle / Serge and Dining Room
- NOIP2014洛谷P2296:寻找道路(bfs)
- CF1375F-Integer Game【交互】
- Loj#143-[模板]质数判定【Miller-Rabin】
- P4027-[NOI2007]货币兑换【斜率优化dp,CDQ分治】
- nssl1186-字串数量【前缀和】