1、准备工作
1.1、慢查询日志
当查询超过一定的时间没有返回结果的话,会记录到慢查询日志中,这个功能有个开关,默认不开启,可以手工开启帮助我们找出执行慢的SQL语句。
查看慢 SQL 日志是否启用(on 表示启用)
show variables like 'slow_query_log'
查看执行慢于多少秒的 SQL 会记录到日志文件中
show variables like 'long_query_time'
1.2、修改MySQL配置参数
my.ini(Linux 下文件名为 my.cnf),查找到[mysqld]区段,增加日志的配置。
Windows 下路径一般为 C:\ProgramData\MySQL\MySQL Server 5.7\my.iniA,可以在启动参数中查看使用的是哪个配置文件。
注意:修改以下参数,需要重新启动数据库服务才会生效。
常用的参数详解
是否开启慢查询日志,1开启,0关闭
slow_query_log=1
指定保存路径及文件名,默认为数据文件目录,
slow_query_log_file="XXXXXXX_slow.log"
指定多少秒返回查询的结果为慢查询,默认10秒
long_query_time=1
记录所有没有使用到索引的查询语句
log_queries_not_using_indexes=1
记录那些由于查找了多于 1000 次而引发的慢查询
min_examined_row_limit=1000
记录那些慢的optimize table,analyze table和alter table语句
log_slow_admin_statements=1
记录由Slave所产生的慢查询
log_slow_slave_statements=1
1.3、命令修改慢查询配置
命令行修改配置方式不需要不重启即可生效,但重启之后会自动失效。
set global slow_query_log=1;
set global slow_query_log_file='bxg_mysql_slow.log';
set long_query_time=1;
set global log_queries_not_using_indexes=1;
set global min_examined_row_limit=1000;
set global log_slow_admin_statements=1;
set global log_slow_slave_statements=1;
1.4、慢日志格式
时间、主机信息、执行信息、执行时间、执行内容
1.5、查询缓存
Query Cache会缓存select查询,但是如果表数据跟结构经常有变化的话,之前的缓存会无效并且删除。这样一定程度上也会影响我们数据库的性能。所以对一些频繁的变动表不要开启缓存
show VARIABLES like 'query_cache_type';
show VARIABLES like 'query_cache_size';
关闭缓存有两种放法,一种临时的,一种永久的。临时的直接在命令行执行
set global query_cache_size=0;
set global query_cache_type=0;
如果配置文件中为关闭缓存的话,不能通过命令开启缓存永久的修改配置文件my.ini,添加下面的配置即可
query_cache_type=0;
query_cache_size=0;
另外,我们还可以通过sql_no_cache关键字在 sql 语句中直接禁用缓存,在开启缓存的情况下我们对sql语句做一些改动
select sql_no_cache count(*) from xxx; -- 不缓存
select sql_cache count(*) from xxx; -- 缓存(也可以不加,默认缓存已经开启了)
2、SQL分析
2.1、EXPLAIN执行计划
查看sql的执行计划
EXPLAIN sql ……
2.2、字段类别
字段 | 说明 |
---|---|
id | 查询中执行select子句或操作表的顺序 |
select_type | 所使用的SELECT查询类型,包括以下常见类型:SIMPLE、 PRIMARY、SUBQUERY、UNION、DERIVED、UNIONRESULT、DEPENDENT、UNCACHEABLE |
table | 所使用的的数据表的名字 |
type | 表示MySQL在表中找到所需行的方式,又称“访问类型”。取值按优劣排序为 NULL > system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL |
possible_keys | 可能使用哪个索引在表中找到记录 |
key | 实际使用的索引 |
Key_len | 索引中使用的字节数 |
ref | 显示索引的哪一列被使用了 |
rows | 估算的找到所需的记录所需要读取的行数 |
filtered | 通过条件过滤出的行数的百分比估计值 |
extra | 包含不适合在其他列中显示但十分重要的额外信息 |
id
包含一组数字,表示查询中执行select子句或操作表的顺序,id相同执行顺序由上至下。如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行。
select_type
所使用的 SELECT 查询类型,包括以下常见类型:
- SIMPLE:表示为简单的SELECT,查询中不包含子查询或者UNION。
- PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为PRIMARY。
- SUBQUERY:在SELECT或WHERE列表中包含了子查询,该子查询被标记为SUBQUERY。
- UNION:表连接中的第二个或后面的select语句,若第二个SELECT出现在UNION之后,则被标记为UNION。
- DERIVED:DERIVED(衍生)用来表示包含在 from 子句中的子查询的 select。若UNION包含在FROM子句的子查询中,外层SELECT 将被标记为DERIVED。mysql会递归执行并将结果放到一个临时表中。服务器内部称为"派生表",因为该临时表是从子查询中派生出来的。
- UNION RESULT:从UNION表获取结果的SELECT被标记为UNION RESULT。
- DEPENDENT:意味着select依赖于外层查询中发现的数据。
- UNCACHEABLE:意味着select中的某些特性阻止结果被缓存于一个item_cache中。
table
所使用的的数据表的名字,他们按被读取的先后顺序排列。
type
表示MySQL在表中找到所需行的方式,又称“访问类型”。取值按优劣排序为NULL > system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL。
一般来说,得保证查询至少达到range级别,最好能达到ref。
- ALL:Full Table Scan全表扫描,MySQL将遍历全表以找到匹配的行。
- index:Full Index Scan全索引扫描,index与ALL区别为index类型只遍历索引树
- range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行。显而易见的索引范围扫描是带有between或者where子句里带有<, >查询。当mysql使用索引去查找一系列值时,例如 IN()和OR列表,也会显示range(范围扫描),当然性能上面是有差异的。
- ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。
- index_merge:该联接类型表示使用了索引合并优化方法。
- unique_subquery:该类型替换了下面形式的IN子查询的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) 。unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
- index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引 : value IN (SELECT key_column FROM single_table WHERE some_expr)
- ref:就是连接程序无法根据键值只取得一条记录,使用索引的最左前缀或者索引不是primary key或unique索引的情况。当根据键值只查询到少数几条匹配的记录时,这就是一个不错的连接类型。
- eq_ref:类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者unique key作为关联条件.
- const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量。注:system是const类型的特例,当查询的表只有一行的情况下,使用system
- NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用。
key
显示 MySQL 在查询中实际使用的索引,若没有使用索引,显示为NULL
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。key_len显示的值为索引字段的最大可能长度,并非实际使用长度。如果键是 NULL,则长度为NULL
ref
显示索引的哪一列被使用了,有时候会是一个常量:表示哪些列或常量被用于用于查找索引列上的值,可能值为库、表、字段、常量、null。
rows
MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数.
filtered
显示了通过条件过滤出的行数的百分比估计值。
extra
包含不适合在其他列中显示但十分重要的额外信息,提供了与关联操作有关的信息,没有则什么都不写。
- Using index:该值表示相应的select操作中使用了覆盖索引(covering Index)。
MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件包含所有满足查询需要的数据的索引称为覆盖索引(covering Index)。
注意:如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。 - using where:表示mysql服务器将在存储引擎检索行后再进行过滤。许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where字句的查询都会显示"using where"。有时"using where"的出现就是一个暗示:查询可受益与不同的索引。
- using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询。这个值表示使用了内部临时(基于内存的)表。一个查询可能用到多个临时表。有很多原因都会导致MySQL在执行查询期间创建临时表。两个常见的原因是在来自不同表的上使用了DISTINCT,或者使用了不同的ORDER BY和GROUP BY列。可以强制指定一个临时表使用基于磁盘的MyISAM存储引擎。这样做的原因主要有两个:1.内部临时表占用的 空间超过min(tmp_table_size , max_heap_table_size系统变量的限制。2.使用了TEXT/BLOB列。
- using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”。
- using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
- impossible where:这个值强调了where语句会导致没有符合条件的行。
- select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行。
- index merges:当MySQL决定要在一个给定的表上使用超过一个索引的时候,就会出现以下格式中的一个,详细说明使用的索引以及合并的类型。
2.3、Profiling的使用
要想优化一条Query,就须要清楚这条Query的性能瓶颈到底在哪里,是消耗的CPU计算太多,还是需要的IO操作太多?要想能够清楚地了解这些信息,可以通过Query Profiler功能得到。
Query Profiler是MYSQL自带的一种query诊断分析工具,通过它可以分析出一条SQL语句的性能瓶颈在什么地方。通常我们是使用的explain,以及slow query log都无法做到精确分析,但是Query Profiler却可以定位出一条SQL语句执行的各种资源消耗情况,比如CPU,IO等,以及该SQL执行所耗费的时间等。
用法:
- 可以通过命令开启关闭QueryProfiler功能
SET global profiling=on;
- 查看相关变量
show VARIABLES like '%profiling%';
- 设置保存数量默认15条,最大值为100
set profiling_history_size=100;
- 在开启Query Profiler功能之后,MySQL就会自动记录所有执行的Query的profile信息
- 获取当前系统中保存的多个Query的profile的概要信息
show profiles;
- 针对单个Query获取详细的profile信息。可以根据概要信息中的Query_ID来获取某个Query在执行过程中详细的profile信息。例如查看cpu和io的详细信息
show profile cpu,block io for query 390;
ALL:显示所有信息show profile ALL for query 390;
BLOCK IO:块设备IO输入输出次数
CONTEXT SWITCHES:上下文切换相关开销
CPU:用户和系统的CPU使用情况
IPC:显示发送和接收消息的相关消耗
MEMORY:内存消耗情况
PAGE FAULTS:显示主要和次要页面故障相关的开销
SOURCE:显示和Source_function,Source_file,Source_line相关的开销信息
SWAPS:显示交换次数相关的开销
注意:profiling被应用在每一个会话中,当前会话关闭后,profiling 统计的信息将丢失。