如何定位慢SQL呢?
我们可以通过 慢查询日志 来查看慢 SQL。
①:开启慢查询日志:
SET global slow_query_log = ON;
:设置慢查询开启的状态(ON:开启;OFF:关闭)slow_query_log_file
:设置慢查询日志存放的位置SET global log_queries_not_using_indexes = ON;
:记录没有使用索引的查询 SQL。前提是slow_query_log
的值为 ON,否则不会奏效SET long_query_time = 10;
:设置慢查询的阀值,单位秒。如果SQL执行时间超过阀值,就属于慢查询 记录到日志文件中②:查看慢查询日志配置:
show variables like 'slow_query_log%
show variables like 'long_query_time'
③:慢查询日志分析工具:
mysqldumpslow
:该工具是慢查询自带的分析慢查询工具,一般只要安装了mysql,就会有该工具
# 取出使用最多的10条慢查询
mysqldumpslow -s c -t 10 /var/run/mysqld/mysqld-slow.log
# 取出查询时间最慢的3条慢查询
mysqldumpslow -s t -t 3 /var/run/mysqld/mysqld-slow.log
# 得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log
# 按照扫描行数最多的
mysqldumpslow -s r -t 10 -g 'left join' /var/run/mysqld/mysqld-slow.log
注意: 使用 mysqldumpslow
的分析结果不会显示具体完整的sql语句,只会显示sql的组成结构;
假如: SELECT * FROM sms_send WHERE service_id=10 GROUP BY content LIMIT 0, 1000;
Count: 1 Time=1.91s (1s) Lock=0.00s (0s) Rows=1000.0 (1000), vgos_dba[vgos_dba]@[10.130.229.196]
SELECT * FROM sms_send WHERE service_id=N GROUP BY content LIMIT N, N;
工具其实还有很多,并不限制只有这一种,还有 pt-query-digest
、mysqlsla
等,这些都是可以定位慢查询日志的小工具
慢查询原因:
<转>详解 慢查询 之 mysqldumpslow
当定位出查询效率低的 SQL 后,可以使用 explain 查看 SQL 的执行计划。
当 explain 与 SQL 一起使用时,MySQL 将显示来自优化器的有关语句执行计划的信息。即:MySQL 解释了它将如何处理该语句,包括有关如何连接表以及以何种顺序连接表等信息:
一般来说,我们需要重点关注 type、key、rows、extra
type 表示连接类型,查看索引执行情况的一个重要指标。以下性能从好到坏依次:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
表示查询时能够使用到的索引(显示的是索引名称),只是可能用到的索引,而不是实际上用到的索引
该列表示实际用到的索引。一般配合 possible_keys
列一起看
MySQL查询优化器会根据统计信息,估算 SQL 要查询到结果需要扫描多少行记录。原则上 rows 是越少效率越高,可以直观的了解到SQL效率高低
该字段包含有关 MySQL 如何解析查询的其他信息,它一般会出现这几个值:
总结:
extra | where 条件 | select 的字段 |
---|---|---|
null | where 筛选条件是索引的前导列 | 查询的列未被索引覆盖 |
Using index | where 筛选条件是索引的前导列 | 查询的列被索引覆盖 |
Using where; Using index | where 筛选条件是索引列之一但不是前导列或者where筛选条件是索引列前导列的一个范围 | 查询的列被索引覆盖 |
Using where; | where 筛选条件不是索引列 | - |
Using where; | where 筛选条件不是索引前导列、是索引列前导列的一个范围(>) | 查询列未被索引覆盖 |
Using index condition | where 索引列前导列的一个范围(<、between) | 查询列未被索引覆盖 |
两种排序的情况:
extra | 出现场景 |
---|---|
Using filesort | filesort主要用于查询数据结果集的排序操作,首先MySQL会使用sort_buffer_size大小的内存进行排序,如果结果集超过了sort_buffer_size大小,会把这一个排序后的chunk转移到file上,最后使用多路归并排序完成所有数据的排序操作。 |
Using temporary | MySQL使用临时表保存临时的结构,以用于后续的处理,MySQL首先创建heap引擎的临时表,如果临时的数据过多,超过max_heap_table_size的大小,会自动把临时表转换成MyISAM引擎的表来使用。 |
filesort 只能应用在单个表上,如果有多个表的数据需要排序,那么MySQL会先使用using temporary保存临时数据,然后再在临时表上使用filesort进行排序,最后输出结果
select_type:表示查询的类型。
常用的值如下:
最常见的查询类型是 SIMPLE
,表示我们的查询没有子查询也没用到 UNION 查询
该列是一个百分比的值,通过查询条件最终查询记录行数和通过 type 字段扫描记录行数的百分比。简单点说,这个字段表示存储引擎返回的数据在经过过滤后,剩下满足条件的记录数量的比例
表示查询使用了索引的字节数量(可以判断是否全部使用了组合索引)
key_len的计算规则如下:
char(n)
:n * 字符集长度varchar(n)
:n * 字符集长度 + 2字节TINYINT
:1个字节SMALLINT
:2个字节MEDIUMINT
:3个字节INT
、FLOAT
:4个字节BIGINT
、DOUBLE
:8个字节DATE
:3个字节TIMESTAMP
:4个字节DATETIME
:8个字节explain 只是看到 SQL 的预估执行计划,如果要了解 SQL 真正的执行线程状态及消耗的时间,需要使用 profiling
开启 profiling 参数后,后续执行的 SQL 语句都会记录其资源开销,包括 IO,上下文切换,CPU,内存等等,我们可以根据这些开销进一步分析当前慢 SQL 的瓶颈再进一步进行优化
查看是否开启 profiling:
show variables like '%profil%'
开启 profiling :
set profiling=ON
使用 profiling :
show profiles
show profiles 会显示最近发给服务器的多条语句,条数由变量 profiling_history_size
定义,默认是 15。如果我们需要看单独某条 SQL 的分析,可以 show profile 查看最近一条 SQL 的分析,也可以使用 show profile for query id
(其中id就是show profiles中的 QUERY_ID)查看具体一条的 SQL 语句分析:
profile 只能查看到 SQL 的执行耗时,但是无法看到 SQL 真正执行的过程信息,即不知道 MySQL 优化器是如何选择执行计划。这时候,我们可以使用 Optimizer Trace
,它可以跟踪执行语句的解析优化执行的全过程
开启:
set optimizer_trace="enabled=on";
查看分析其执行树,会包括三个阶段:
确认问题,就采取对应的措施。