Mysql慢查询日志分析和Mysql优化

MySQL5.7.26的安装详见:https://blog.csdn.net/niuxitong/article/details/89915566

一、慢查询日志的概念

1、MySQL中的日志

MySQL日志文件系统的组成
   a、错误日志:记录启动、运行或停止mysqld时出现的问题。
   b、通用日志:记录建立的客户端连接和执行的语句。
   c、更新日志:记录更改数据的语句。该日志在MySQL 5.1中已不再使用。
   d、二进制日志:记录所有更改数据的语句。还用于复制。
   e、慢查询日志:记录所有执行时间超过long_query_time秒的所有查询或不使用索引的查询。
   f、Innodb日志:innodb redo log
        缺省情况下,所有日志创建于mysqld数据目录中。同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分。MySQL有几种不同的日志文件,通常包括错误日志文件,二进制日志,通用日志,慢查询日志,等等。这些日志可以帮助我们定位mysqld内部发生的事件,数据库性能故障,记录数据的变更历史,用户恢复数据库等等。今天我们要讲的是如何分析和查询mysql慢日志(主要影响程序调用和前端数据呈现)。

2、什么是慢查询

        MySQL的慢查询日志是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阈值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中(日志可以写入文件或者数据库表,如果对性能要求高的话,建议写文件)。long_query_time的默认值为10(即10秒,通常设置为1秒),即运行10秒以上的语句是慢查询语句。

        默认情况下,Mysql数据库并不启动慢查询日志(即slow_query_log参数值为OFF),需要我们手动来设置这个参数,如果不是调优需要,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。

3、慢查询相关参数

slow_query_log=1        # 是否开启慢查询日志,1表示开启,0表示关闭。
long_query_time=1        # 慢查询阈值秒,默认值为10秒,通常设置为1秒,当查询时间多于设定的阈值时,记录日志。
slow-query-log-file=/usr/local/mysql/data/localhost-slow.log    #新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件 服务器名-slow.log,并保存到datadir目录下

#log-slow-queries  :旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件 服务器名-slow.log,并保存到datadir目录下
#log_queries_not_using_indexes=0        # 1表示开启,0表示关闭。  如果值设置为ON,未使用索引的查询也被记录到慢查询日志中(性能优化时开启此项,平时不要开启)开启了这个参数,其实使用full index scan的sql也会被记录到慢查询日志
#log_output='FILE'        # 日志存储方式,默认值是'FILE',文件效率高

其中 #log_output='TABLE'表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中。MySQL数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:log_output='FILE,TABLE'。日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件。

二、设置慢查询 

1、查看慢查询日志的开启状态和慢查询日志储存的位置

mysql> show variables like '%query%';   
mysql> show variables like '%slow_query_log%';

Mysql慢查询日志分析和Mysql优化_第1张图片

2、开启临时慢查询

#开启了慢查询日志只对当前数据库生效,MySQL重启后则会失效。如果要永久生效,就必须修改配置文件my.cnf(其它系统变量也是如此)
mysql> set global slow_query_log=1;         #开启慢查询 
mysql> set global slow_query_time=1;        #设置阈值为1秒
mysql> set global slow_query_log_file='/usr/local/mysql/log/qinser-slow.log'        #重新定义慢查询日志的存放目录

Query OK, 0 rows affected (0.01 sec)

mysql> show variables like '%slow_query_log%';

+---------------------+---------------------------------------+
| Variable_name       | Value                                 |
+---------------------+---------------------------------------+
| slow_query_log      | ON                                    |  <----ON已经开启
| slow_query_log_file | /usr/local/mysql/data/qinser-slow.log |
+---------------------+---------------------------------------+


mysql> set global long_query_time=1;  #设置阈值为1秒
Query OK, 0 rows affected (0.00 sec)

mysql> 
mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |   <------上面已经修改过了,为什么这里还是10呢???
+-----------------+-----------+
#注意:使用命令 set global long_query_time=4修改后,需要重新连接或新开一个会话才能看到修改值。你用show variables like 'long_query_time'查看是当前会话的变量值,你也可以不用重新连接会话,而是用show global variables like 'long_query_time';

mysql> show global variables like 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+


#-- 设置慢查询的存储方式-- 默认为FILE 。如果要修改,使用以下方法,其值可以为 'file'|'table'|'file,table'
mysql> set global log_output='file'; 

mysql> show variables like '%log_output%';  

3、永久开启慢查询
 把配置项写入/etc/my.cnf配置文件中

slow_query_log=1                # 是否开启慢查询,默认不开启,1开启 0不开启
slow_query_log_file=/usr/local/mysql/log/qinser-slow.log   #自定义默认慢查询日志   
long_query_time=1

然后重启mysql (必须使用 restart, 使用reload可能无效)这时已经在数据库文件存放目录生成了qinser-slow.log文件。

三、分析慢查询

1、创建演示数据

# 建表语句:
CREATE TABLE `qs_news` (
  `id` INT(10) NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(50) DEFAULT NULL COMMENT '新闻标题',
  `keywords` VARCHAR(50) DEFAULT NULL COMMENT '关键词',
  `author` VARCHAR(20) DEFAULT NULL COMMENT '作者',
  `contents` TEXT COMMENT '内容',
  `status` TINYINT(2) DEFAULT '1' COMMENT '状态 1:正常 0:删除',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='新闻文章表';

创建演示数据,有针对向的向表里手工添加一条数据,注意contents字段尽可能的内容多写,然后使用sql 蠕虫复制(这种生成数据方式同样适用于数据表中有主键的情况)

INSERT INTO qs_news (title,keywords,author,contents,create_time) SELECT title,keywords,author,contents,create_time FROM qs_news;

2、读取慢日志文件

# vim /usr/local/mysql/log/qinser_slow.log

Mysql慢查询日志分析和Mysql优化_第2张图片

其中:# Time与 SET timestamp  表示慢查询SQL发生的日期时间,  # Query_time:3.447456 表示此条语句执行的秒数。 

3、慢查询工具mysqldumpslow  

mysqldumpslow 是msyql自带的工具,位于/usr/local/mysql/bin/目录下,mysql安装成功后就可以全局使用。

# mysqldumpslow --help 
# mysqldumpslow /usr/local/mysql/log/qinser-slow.log                #查询所有
# mysqldumpslow -s r -t 10 /usr/local/mysql/log/qinser-slow.log     #得到返回记录集最多的10个SQL
# mysqldumpslow -s c -t 10 /usr/local/mysql/log/qinser-slow.log     #得到访问次数最多的10个SQL
# mysqldumpslow -s t -t 10 -g 'left join' /usr/local/mysql/log/qinser-slow.log      #得到按照时间排序的前10条里面含有左连接的查询语句

# mysqldumpslow /usr/local/mysql/log/qinser-slow.log | more     #建议在使用这些命令时结合 | 和more 使用 ,否则有可能出现刷屏的情况。

常用参数:

-s, 是表示按照何种方式排序,

c: 访问计数
l: 锁定时间
r: 返回记录
t: 查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间

-t, 是top n的意思,即为返回前面多少条的数据;

-g, 后边可以写一个正则匹配模式,大小写不敏感的;

4、pt-query-digest工具的使用
       需要自己安装pt-query-digest。pt-query-digest工具相较于mysqldumpslow功能多一点。

(1)安装

# yum -y install perl-DBI
# yum -y install perl-DBD-MySQL
# yum -y install perl-Time-HiRes
# yum -y install perl-IO-Socket-SSL
# yum -y install perl-Digest-MD5-2.52-3.el7.x86_64
# cd /mydata/
# wget percona.com/get/pt-query-digest
# chmod u+x pt-query-digest 
# mv pt-query-digest  /usr/bin/  

# pt-query-digest --help               #查看参数

(2)使用:

# pt-query-digest /usr/local/mysql/log/qinser-slow.log 

Mysql慢查询日志分析和Mysql优化_第3张图片 

查询结果分为三部分:

第一部分:显示出了日志的时间范围,以及总的sql数量和不同的sql数量
第二部分:显示出统计信息
第三部分:每一个sql具体的分析(与第一部分的Query ID 键值对应)
其中: pct是percent的简写,表示占的百分比,cout是占总sql个数的百分比,exec time 是占总执行时间的百分比,lock time 表示占总的锁表时间的百分比。 这三个数的比例越大,越需要关注。
(3)如何通过pt-query-digest 慢查询日志发现有问题的sql
1)查询次数多且每次查询占用时间长的sql:通常为pt-query-digest分析的前几个查询
2)IO消耗大的sql 注意pt-query-digest分析中的Rows examine项
3)为命中索引的sql

注意pt-query-digest分析中Rows examine(扫描行数) 和 Rows sent (发送行数)的对比 ,如果扫描行数远远大于发送行数,则说明索引命中率并不高。
 

四、对SQL进行优化

通过上面的慢查询,我们可以得到哪些sql语句执行的慢,然后对这些语句进行分析

1、使用explain查询sql的执行计划

# mysql -u root -p
# use ecshop
# explain select * from `qs_news` where contents like '%AAA%' and title like '%李四%';

+----+-------------+---------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+-------+----------+-------------+
|  1 | SIMPLE      | qs_news | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 41507 |     1.23 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+-------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

参数分析:
table:表示属于哪张数据表
type:最重要的参数,表示连接使用了何种类型。从最好到最差的连接类型为const,eq_reg,ref,range,index和ALL。
possible_keys:显示可能应用在这张表中的索引。如果为null,则表示没有可能的索引。
key:实际使用的索引。如果为null,则表示没有使用索引。
key_len:使用的索引的长度,在不损失精确性的情况下,长度越短越好。
ref:表示索引的哪一列被使用了,如果可能的话,是一个常数。
rows:Mysql认为必须检查的用来返回请求数据的行数。

2、count()和 Max()的优化方法

对于max()的字段建立索引,能加快查询。


3、对子查询的优化
4、group by 的优化
5、Limit的优化

五、对索引进行优化
1、选择合适的列建立索引

2、索引优化sql的方法

3、索引维护的方法

 

六、数据库结构优化
1、选择合适的数据类型

2、数据库表的范式化优化

3、数据库表的反范式优化

4、数据库表的垂直拆分

5、数据库表的水平拆分

 

七、系统配置优化
1、数据库系统配置优化

2、Mysql配置文件优化

3、第三方配置工具使用

八、服务器硬件优化
 

你可能感兴趣的:(Mysql)