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性能; 
 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330557.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何把模型表导入数据库

开发工具与关键技术&#xff1a;Power Designer、SQL 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.05.23事先说明&#xff0c;我只是一个小萌新&#xff0c;我分享的文章是我在学习过程中学到的&#xff0c;不代表全是正确的&#xff0c;所以我要是有什么地方说错了&#x…

解决eclipse中tomcat无法识别maven web项目问题

eclipse工具中导入了maven web项目, 但是tomcat死活都识别不了, maven项目进行了clean install等操作, 但是仍无效, 后在网上搜索到以下答案, 解决问题 1. 右击项目 -> Debug As -> Maven build... 2. 在Goals中填入: -Dwtpversion2.0 eclipse:eclipse 对于WTP(Web Tool…

深入理解CAS算法原理

转载自 深入理解CAS算法原理1、什么是CAS&#xff1f;CAS&#xff1a;Compare and Swap&#xff0c;即比较再交换。jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronouse同步锁的一种乐观锁。JDK 5之前Java语言是靠synchronized关键字保证同…

如何写登录的记住账号

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.05.27上次我把如何登录的代码给写了&#xff0c;却没有写如何记住登录的账号密码&#xff0c;所以现在我就简单的写一下是如何记住账号密码的。 如果我们没写记住密码的话&am…

严重: Error configuring application listener of class org.springframework.web.context.ContextLoaderLis

博主 使用Eclipse 下的Mavn搭建的SSM框架的工程&#xff0c;出现以下错误 严重: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener Java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoad…

java高级应用:线程池全面解析

转载自 java高级应用&#xff1a;线程池全面解析 什么是线程池&#xff1f; 很简单&#xff0c;简单看名字就知道是装有线程的池子&#xff0c;我们可以把要执行的多线程交给线程池来处理&#xff0c;和连接池的概念一样&#xff0c;通过维护一定数量的线程池来达到多个线程的复…

如何用for循环出数据库的数据

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.5.30在客房管理的系统中有很多不同的小格子&#xff0c;它们分别代表了不同的房间&#xff0c;可以动态的显示每间房间的状态&#xff0c;这个就是房态图。有很多系统应该都有…

Maven常见问题之【-Dmaven.multiModuleProjectDirctory system property is not set】

配置jdk时&#xff0c;声明vm参数&#xff0c;如下&#xff0c; 且需要保证 M2_HOME 环境变量已经配置了&#xff0c; 如下&#xff1a; C:\Users\pacoson>echo %M2_HOME% D:\software_cluster\apache-maven-3.3.9 -Dmaven.multiModuleProjectDirectory$M2_HOME

实现java多线程的3种方式,99%人没用过第3种

转载自 实现java多线程的3种方式&#xff0c;99%人没用过第3种 实现多线程的3种方式 1、继承Thread类 看jdk源码可以发现&#xff0c;Thread类其实是实现了Runnable接口的一个实例&#xff0c;继承Thread类后需要重写run方法并通过start方法启动线程。 继承Thread类耦合性太强了…

关于时间类型的问题

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.6.2我在做项目的时候遇到了一个问题&#xff0c;我要把时间显示到表格上&#xff0c;然后我像平常那样写&#xff0c;linq查询&#xff0c;然后返回数据&#xff0c;然后加载…

maven项目不编译xml文件

最近在搭建一个mavenspringMVCmybatis的项目&#xff0c;编译的时候mybatis生成的**Mapper.xml文件总是不编译&#xff08;classes文件夹内没有出现&#xff09;。 解决方法是在maven的pom.xml文件夹<build>标签下增加如下代码&#xff08;build标签的父标签是 project标…

多线程并发神器--ThreadLocal

转载自 多线程并发神器--ThreadLocal什么是ThreadLocal可以理解成线程本地变量&#xff0c;传统的线程对一个变量操作时操作的是同一个对象&#xff0c;也存在线程安全的问题。ThreadLocal是一个变量的本地副本&#xff0c;线程对变量的操作不会影响其他线程。首先看看ThreadLo…

如何获取复选框的值

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.6.7我们在很多地方都用到了复选框&#xff0c;数据表格里也有复选框&#xff0c;新增数据时也可能要复选框&#xff0c;修改时也要回填复选框&#xff0c;所以我们用到的地方…

使用log4j2打印mybatis的sql执行日志

【1】maven配置jar包依赖&#xff0c; 如下&#xff1a; <!-- 日志jar --><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-…

Java多线程神器:join使用及原理

转载自 Java多线程神器&#xff1a;join使用及原理 join() join()是线程类 Thread的方法&#xff0c;官方的说明是&#xff1a; Waits for this thread to die. 等待这个线程结束&#xff0c;也就是说当前线程等待这个线程结束后再继续执行&#xff0c;下面来看这个示例就明白…

页面残留数据该如何处理

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.6.13关于页面数据残留的问题&#xff0c;我前几天就遇到了&#xff0c;刚开始的时候我写完那个页面是不知道它有毛病的&#xff0c;后来我才发现了它居然有一个小问题。 先来…

基于maven的SpringMVC+Spring+MyBatis+Log4j2的pom配置

【0】README&#xff1a;本文旨在给出可以正常跑 测试用例的项目依赖配置&#xff0c; 同时还会给出 maven 编译项目时的坑儿&#xff1b; 【1】 pom配置&#xff1a; <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/20…

一张图弄懂java线程的状态和生命周期

转载自 一张图弄懂java线程的状态和生命周期 上图是一个线程的生命周期状态流转图&#xff0c;很清楚的描绘了一个线程从创建到终止的过程。 这些状态的枚举值都定义在java.lang.Thread.State下 NEW&#xff1a;毫无疑问表示的是刚创建的线程&#xff0c;还没有开始启动。 RUNN…

如何添加数据到session中

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.6.17我们都知道session相当于服务器的一次对话&#xff0c;服务器会为每个新的用户创建一个新的 Session&#xff0c;并在 session 到期时撤销掉这个 Session 对象。所以sess…

MySQL8.0: Serialized Dictionary Information(SDI) 浅析

转自&#xff1a; https://yq.aliyun.com/articles/600183 SDI是Serialized Dictionary Information的缩写&#xff0c;是MySQL8.0重新设计数据词典后引入的新产物。我们知道MySQL8.0开始已经统一使用InnoDB存储引擎来存储表的元数据信息&#xff0c;但对于非InnoDB引擎&#…