MySQL进阶(五)——查询截取分析

本篇文章主要是对MySQL学习时的一些总结,作为学习笔记记录

查询截取分析

慢查询日志

慢查询日志是什么

  • MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阈值的语句
  • 具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中
  • long_query_time的默认值为10,意思是运行10秒以上的语句
  • 通过查看哪些SQL超出了我们的最大忍耐时间值,结合之前explain进行全面分析
     

慢查询日志怎么用

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

查看是否开启及如何开启

# 查看参数设置,默认为OFF,表示禁用
SHOW VARIABLES LIKE '%slow_query_log%';

# 开启慢查询日志
SET GLOBAL slow_query_log = 1; 

开启慢查询日志后,什么样的sql语句才会被记录到慢查询日志当中呢?这个可以查看long_query_time变量:

该值可以通过命令修改,也可以在my.cnf配置文件中修改。

在my.cnf配置文件中配置为:

# [mysqld]
slow_query_log=1;
slow_query_log_file=/var/lib/mysql/atguigu-slow.log
long_query_time=3;
log_output=FILE

 通过命令行修改为:

修改后发现并没有什么变化,这是因为需要重新连接或者新开一个会话才能看到修改后的值,重新打开一个新的会话查看参数:

也可以通过修改会话变量进行设定:

但是如果运行时间正好等于long_query_time的情况,并不会被记录下来。也就是说,在mysql源码里是判断大于long_query_time,而非大于等于。

产生一条慢sql

对应的慢查询日志中的内容为:

查看当前系统中有多少条慢查询记录

SHOW GLOBAL STATUS LIKE 'Slow_queries';

日志分析工具mysqldumpslow

mysqldumpslow提供了对慢查询日志文件的分析。

帮助信息

‘mysqldumpslow的帮助信息为:

各参数的含义为:

  • s: 是表示按照何种方式排序
  • c: 访问次数
  • l: 锁定时间
  • r: 返回记录
  • t: 查询行数
  • al:平均锁定时间
  • ar:平均返回记录数
  • at:平均查询时间
  • t:即为返回前面多少条的数据
  • g:后边搭配一个正则匹配模式,大小写不敏感的

工作常用参考

# 得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /usr/local/mysql/data/sakura-mysql-slow.log
 
# 得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 /usr/local/mysql/data/sakura-mysql-slow.log
 
# 得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g "left join" /usr/local/mysql/data/sakura-mysql-slow.log
 
# 另外建议在使用这些命令时结合 | 和more 使用 ,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 /usr/local/mysql/data/sakura-mysql-slow.log | more

批量数据脚本

往表中插入1000W条数据

建表

# 新建库
CREATE DATABASE bigData;
USE bigData;

#1 建表dept
CREATE TABLE dept (
  id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
  dname VARCHAR (20) NOT NULL DEFAULT "",
  loc VARCHAR (13) NOT NULL DEFAULT ""
) ENGINE = INNODB DEFAULT CHARSET = UTF8 ;


#2 建表emp
CREATE TABLE emp (
  id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
  ename VARCHAR (20) NOT NULL DEFAULT "",
  job VARCHAR (9) NOT NULL DEFAULT "",
  mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
  hiredate DATE NOT NULL,
  sal DECIMAL (7, 2) NOT NULL,
  comm DECIMAL (7, 2) NOT NULL,
  deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0
) ENGINE = INNODB DEFAULT CHARSET = UTF8 ;

创建函数

随机产生字符串:

DELIMITER $$

CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
  DECLARE chars_str VARCHAR(100) DEFAULT   'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; 
  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 $$

CREATE FUNCTION rand_num( ) RETURNS INT(5)  
BEGIN   
  DECLARE i INT DEFAULT 0;  
  SET i = FLOOR(100+RAND()*10);  
  RETURN i;  
END $$

如果出现下述的错误:

则需要首先执行下述语句:

SHOW VARIABLES LIKE 'log_bin_trust_function_creators';

SET GLOBAL log_bin_trust_function_creators=1;

创建存储过程

创建往emp表中插入数据的存储过程:

DELIMITER $$

CREATE PROCEDURE insert_emp(IN START INT(10),IN max_num INT(10))  
BEGIN  
  DECLARE i INT DEFAULT 0;   
  SET autocommit = 0;    
  
  REPEAT
    SET i = i + 1;  
    INSERT INTO emp (empno, ename ,job ,mgr ,hiredate ,sal ,comm ,deptno ) VALUES ((START+i) ,rand_string(6),'SALESMAN',0001,CURDATE(),FLOOR(1+RAND()*20000),FLOOR(1+RAND()*1000),rand_num());  
    UNTIL i = max_num
  END REPEAT;
  
  COMMIT;
END $$

创建往dept表中插入数据的存储过程:

DELIMITER $$

CREATE PROCEDURE insert_dept(IN START INT(10),IN max_num INT(10))  
BEGIN  
  DECLARE i INT DEFAULT 0;   
  SET autocommit = 0;    
  
  REPEAT  
    SET i = i + 1;  
    INSERT INTO dept (deptno ,dname,loc ) VALUES (START +i ,rand_string(10),rand_string(8));  
    UNTIL i = max_num  
  
  END REPEAT;  
  COMMIT;  
 END $$ 

调用存储过程

dept:

DELIMITER ;
CALL insert_dept(100,10); 

emp:

#执行存储过程,往emp表添加50万条数据
DELIMITER ;
CALL insert_emp(100001,500000); 

大量数据案例

emp表结构为:

执行explain分析:

从上图的结果来看,type的类型为all,extra中出现了filesort,因此需要优化。

尝试建立组合索引:

CREATE INDEX idx_dno_eno_ena ON emp(deptno,empno,ename);

进行explain分析:

从上述结果看出,filesort仍然存在,因此ename并没有用到索引(empno是一个范围,empno之后的字段不会用到索引),还需要继续进行优化。

删除索引并建立新的索引:

DROP INDEX idx_dno_eno_ena ON emp;
CREATE INDEX idx_dno_ena ON emp(deptno,ename);

进行explain分析:

从上面的结果可以看出,type的类型变为了ref,filesort消失了,

而如果建立idx_dno_eno索引是什么情况呢?

DROP INDEX idx_dno_ena ON emp;
CREATE INDEX idx_dno_eno ON emp(deptno,empno);

从上面的结果可以看出,仍然存在filesort,这意味着排序没有使用到索引。

但对比运行速度来看,存在filesort的sql运行速度超过了已经优化掉filesort的sql,这是什么原因?

  • 原因是所有的排序都是在条件过滤之后才执行的,所以如果条件过滤了大部分数据的话,几百几千条数据进行排序其实并不是很消耗性能,即使索引优化了排序但实际提升性能很有限。  相对的 empno<100100 这个条件如果没有用到索引的话,要对几万条的数据进行扫描,这是非常消耗性能的,所以索引放在这个字段上性价比最高,是最优选择。
  • 结论:当范围条件和group by或者 order by的字段出现二选一时 ,观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之亦然

show profile

show profile是什么

  • show profile是mysql提供可以用来分析当前会话中语句执行的资源消耗情况。
  • 可以用于SQL的调优的测量
  • 官网介绍:http://dev.mysql.com/doc/refman/5.5/en/show-profile.html

默认情况下,参数处于关闭状态,并保存最近15次的运行结果。

分析步骤

查看当前版本是否支持

SHOW  VARIABLES LIKE 'profiling';

开启功能

默认关闭,使用前需要开启

运行sql语句

SELECT * FROM emp GROUP BY id%10 LIMIT 150000;

SELECT * FROM emp GROUP BY id%20 ORDER BY 5;

查看结果

SHOW profiles;

诊断sql语句

# n为上一步sql的Query_ID
SHOW profile cpu,block io FOR QUERY n;

各个参数的含义为:

  • ALL:显示所有的开销信息  
  • BLOCK IO:显示块IO相关开销  
  • CONTEXT SWITCHES:上下文切换相关开销  
  • CPU:显示CPU相关开销信息  
  • IPC:显示发送和接收相关开销信息  
  • MEMORY:显示内存相关开销信息  
  • PAGE FAULTS:显示页面错误相关开销信息  
  • SOURCE:显示和Source_function,Source_file,Source_line相关的开销信息  
  • SWAPS:显示交换次数相关开销的信息

日常开发需要注意的结论

  • converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬
  • Creating tmp table 创建临时表,拷贝数据到临时表,用完再删除,整个过程比较耗费时间
SELECT * FROM emp GROUP BY id%20 LIMIT 120000;
SELECT * FROM emp GROUP BY id%20 ORDER BY 5;

  • Copying to tmp table on disk 把内存中临时表复制到磁盘,危险
  • locked

全局查询日志

尽量不要在生产环境开启该功能。

配置启用

在mysql的my.cnf中,设置如下:

# 开启
general_log=1   

# 记录日志文件的路径
general_log_file=/path/logfile

# 输出格式
log_output=FILE

编码启用

# 开启
set global general_log=1;
 
# 全局日志可以存放到日志文件中,也可以存放到Mysql系统表中
# 存放到日志中性能更好一些
# 存储到表中:
set global log_output='TABLE';

# 之后,编写的sql语句将会记录到mysql库里的general_log表,可以用下面的命令查看
select * from mysql.general_log;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值