慢SQL 慢查询实践

1. 获取慢查询SQL方式

  • 已经执行完的SQL,检查慢查询日志,日志中有执行慢的SQL

  • 正在执行中的SQLshow processlist;,结果中有执行慢的SQL

2. 查看慢查询配置语句

2.1 慢日志是否开启和日志文件位置

mysql> show variables like '%slow_query_log%';
+---------------------+----------------+
| Variable_name       | Value          |
+---------------------+----------------+
| slow_query_log      | OFF            |
| slow_query_log_file | bogon-slow.log |
+---------------------+----------------+

2.2 慢日志阈值

mysql> show variables like '%long_query_time%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+

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

mysql> show global status like '%Slow_queries%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries  | 0     |
+---------------+-------+

3. 开启慢查询日志

  1. 默认情况下,MySQL没有开启慢查询日志。需要手动打开

  2. 不建议开启,因为开启会带来一定的性能影响

3.1 临时开启

不需要重启mysql,不区分系统,简单方便。重启mysql配置就失效了。

# 开启慢查询日志,只对当前数据库生效,并且重启数据库后失效
set global slow_query_log = 1;# 设置阈值
set long_query_time = 3;#设置慢日志文件
SET GLOBAL slow_query_log_file = '/mysql-slow.log';

3.2 永久开启

修改配置文件my.cnf,新增如下内容。
完成配置后,需要重启MySQL服务器才能使配置生效。

[mysqld]## 开启慢查询日志,开启后将会记录执行时间超过 long_query_time 参数值的 SQL 语句( 一般临时开启即可 )
slow_query_log = 1## 定义执行时间超过多少秒为慢查询,默认 10s
long_query_time = 1## 定义慢查询日志存放位置
slow_query_log_file = /data/mysql/logs/slow.log

冷暖自知一抹茶ck


#### slow log  慢查询日志 ####
slow_query_log = 1                       ## 开启慢查询日志
slow_query_log_file = slow.log     ## 慢查询日志文件名称
long_query_time = 2                     ##sql 语句超过2s就记录
min_examined_row_limit = 100    ## sql执行中examined_row 取出数据必须大于100行才会记录
log-queries-not-using-indexes     ## 没有使用索引SQL的sql记录到慢查询
log_throttle_queries_not_using_indexes = 5 ## 限制每分钟记录没有使用索引Sql的次数 意思就是:一条sql语句一直在记录 记录太多了 占存储 一分钟只记录5次
log-slow-admin-statements = table   ##记录管理的操作,例如alter | analyze talbe 命令
log_output = file                                 ## 记录慢查询日志的格式 FILE|TABLE|NONE 默认是文件格式 TABLE 是以表的格式 不建议用table
log_timestamps = 'system'                 ## 慢日志记录的时间格式 采用系统的时间

4. MySQL–慢查询日志

4.1慢查询日志

慢日志文件默认是在我们配置的data_dir目录下面的机器名+-slow.log文件

冷暖自知一抹茶ck


Time执行的时间 这里的时间时区是不对的,可以通过log_timestamps = system设置 

Query_time是sql的运行时间,
Lock_time是sql锁住的时间
Row_wxamined: 表示这个sql读取行数
Rows_sent:返回的行总数

4.2 mysqldumpslow 命令 常见的分析和优化查询日志文件语句如下

能将相同的慢SQL归类,并统计出相同的SQL执行的次数,每次执行耗时多久、总耗时,每次返回的行数、总行数,以及客户端连接信息等。

4.2.1、查看帮助

cd /data/mysql/install/bin/./mysqldumpslow  --help

内容

[root@crc-uat-oa-mysql bin]# ./mysqldumpslow  --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]Parse and summarize the MySQL slow query log. Options are  --verbose    verbose  --debug      调试  --help       帮助文档  -v           verbose  -d           调试
  # 表示按何种方式排序  -s ORDER     what to sort by (al, at, ar, c, l, r, t), 'at' is default
                al: 平均 锁定时间
                ar: 平均 返回记录
                at: 平均 查询时间
                 c:   访问次数
                 l:   锁定时间
                 r:  返回记录
                 t:  查询时间  -r           颠倒排序顺序(最大的最后一个而不是第一个)  -t NUM       返回前面多少条数据  -a           don't abstract all numbers to N and strings to 'S'  -n NUM       abstract numbers with at least n digits within names  -g PATTERN   后面搭配一个正则匹配模式,大小写不敏感。  -h HOSTNAME  数据库服务器的主机名 for *-slow.log 文件,默认是 '*', 表示匹配所有 
  -i NAME      服务器实例的名称(如果使用mysql.server启动脚本  -l           不要从总时间中减去锁定时间

4.2.2 汇总:

#锁定时间最长的前10条
mysqldumpslow.pl -s l -t 1 mysql_slow.log

#得到返回记录集最多的10个SQL
mysqldumpslow.pl -s r -t 10 mysql_slow.log

#按照扫描行数最多的前10条  有left join 的语句
mysqldumpslow -s r -t 10 -g 'left join' /var/log/mysql/mysql-slow.log  

#得到访问次数最多的10个SQL
mysqldumpslow.pl -s c -t 10 mysql_slow.log

#按查询总时间排序,显示前10条查询信息取出查询时间最慢的10条慢查询)mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log

#得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g “left join” /var/log/mysql/mysql-slow.log 

# 另外建议在使用这些命令时结合| 和more 使用,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 /data/mysql/logs/slow.log | more

其中,-s t 表示按查询总时间排序,-s c表示按查询次数排序,-t 10表示显示前10条查询信息。
widows下使用mysqldumpslow 可以参考:Windows下安装使用mysqldumpslow

4.3 explain分析慢查询SQL

explain关键参数

名称解释
key实际用到的索引列
type索引类型
extra额外信息

type部分值

名称解释
consts基于主键或唯一索引查询,最多返回一条数据,优化阶段可得到数据
ref基于普通索引的等值查询,表间等值连接
range利用索引范围查询
index全索引扫描
ALL全表操作

Extra部分值

名称解释
Using index使用覆盖索引,减少表扫描和回表
Using index condition先条件过滤索引再查询数据
Using filesort使用外部排序,非索引排序
Using where使用where条件
Impossible wherewhere总是false
Using temporary使用临时表,一般发生在order by无索引列时
Using join buffer (Block Nested Loop)在进行嵌套循环连接,内表大
Select tables optimized away该查询不需要访问实际的表,而是通过优化方式直接计算出结果

select_type部分值

名称解释
Simple简单查询
Primary关联查询或子查询的外层查询
Unoin关联查询或子查询的后续查询

5. 正在执行中的SQL

show processlist 其实查询的是 information_schema.processlist 表.
show processlist 不可以接 where 过滤,information_schema.processlist 表可以

show processlist 是显示用户正在运行的线程,需要注意的是,除了 root 用户能看到所有正在运行的线程外,其他用户都只能看到自己正在运行的线程,看不到其它用户正在运行的线程。除非单独个这个用户赋予了PROCESS 权限。

mysql> show processlist;
+----+------+-----------------+------+---------+------+----------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+------+---------+------+----------+------------------+
| 51 | root | localhost:61246 | test | Sleep | 0 | | NULL |
| 52 | root | localhost:61342 | test | Query | 0 | starting | show processlist |
+----+------+-----------------+------+---------+------+----------+------------------+
2 rows in set (0.10 sec)

了解这些基本信息后,下面我们看看查询出来的结果都是什么意思。

  • Id: 就是这个线程的唯一标识,当我们发现这个线程有问题的时候,可以通过 kill 命令,加上这个Id值将这个线程杀掉。前面我们说了show processlist 显示的信息时来自information_schema.processlist 表,所以这个Id就是这个表的主键。

  • User: 就是指启动这个线程的用户。

  • Host: 记录了发送请求的客户端的 IP 和 端口号。通过这些信息在排查问题的时候,我们可以定位到是哪个客户端的哪个进程发送的请求。

  • DB: 当前执行的命令是在哪一个数据库上。如果没有指定数据库,则该值为 NULL 。

  • Command: 是指此刻该线程正在执行的命令。这个很复杂,下面单独解释

  • Time: 表示该线程处于当前状态的时间。

  • State: 线程的状态,和 Command 对应,下面单独解释。

  • Info: 一般记录的是线程执行的语句。默认只显示前100个字符,也就是你看到的语句可能是截断了的,要看全部信息,需要使用 show full processlist。

下面我们单独看一下 Command 的值:

  • Binlog Dump: 主节点正在将二进制日志 ,同步到从节点

  • Change User: 正在执行一个 change-user 的操作

  • Close Stmt: 正在关闭一个Prepared Statement 对象

  • Connect: 一个从节点连上了主节点

  • Connect Out: 一个从节点正在连主节点

  • Create DB: 正在执行一个create-database 的操作

  • Daemon: 服务器内部线程,而不是来自客户端的链接

  • Debug: 线程正在生成调试信息

  • Delayed Insert: 该线程是一个延迟插入的处理程序

  • Drop DB: 正在执行一个 drop-database 的操作

  • Execute: 正在执行一个 Prepared Statement

  • Fetch: 正在从Prepared Statement 中获取执行结果

  • Field List: 正在获取表的列信息

  • Init DB: 该线程正在选取一个默认的数据库

  • Kill : 正在执行 kill 语句,杀死指定线程

  • Long Data: 正在从Prepared Statement 中检索 long data

  • Ping: 正在处理 server-ping 的请求

  • Prepare: 该线程正在准备一个 Prepared Statement

  • ProcessList: 该线程正在生成服务器线程相关信息

  • Query: 该线程正在执行一个语句

  • Quit: 该线程正在退出

  • Refresh:该线程正在刷表,日志或缓存;或者在重置状态变量,或者在复制服务器信息

  • Register Slave: 正在注册从节点

  • Reset Stmt: 正在重置 prepared statement

  • Set Option: 正在设置或重置客户端的 statement-execution 选项

  • Shutdown: 正在关闭服务器

  • Sleep: 正在等待客户端向它发送执行语句

  • Statistics: 该线程正在生成 server-status 信息

  • Table Dump: 正在发送表的内容到从服务器

  • Time: Unused

下面是常用到的SQL,记录下来便于使用。

按客户端 IP 分组,看哪个客户端的链接数最多

select client_ip,count(client_ip) as client_num from (select substring_index(host,':' ,1) as client_ip from processlist ) as connect_info group by client_ip order by client_num desc;

查看正在执行的线程,并按 Time 倒排序,看看有没有执行时间特别长的线程

select * from information_schema.processlist where Command != 'Sleep' order by Time desc;

找出所有执行时间超过 5 分钟的线程,拼凑出 kill 语句,方便后面查杀

select concat('kill ', id, ';') from information_schema.processlist where Command != 'Sleep' and Time > 300 order by Time desc;






冷暖自知一抹茶ck
请先登录后发表评论
  • 最新评论
  • 总共0条评论