MySQL 性能分析
# 执行频率
通过以下命令可以查看当前数据库的访问频次信息:
SHOW [SESSION|GLOBAL] STATUS; -- session表示查看当前会话,global表示查看全局
通过该指令我们可以查看到当前数据库到底是以查询为主,还是以增删改为主,从而为数据库优化提供参考依据。如果是以增删改为主,我们可以考虑不对其进行索引的优化。如果是以查询为主,那么就要考虑对数据库的索引进行优化了。
# 慢查询日志
慢查询日志记录了所有执行时间超过long_query_time
参数(默认 10 秒)并不小于min_examined_row_limit
的所有 SQL 语句的日志。可以通过show variables like 'slow_query_log'
查看是否开启了慢查询日志,默认是不开启(OFF)的。
如果要开启慢查询日志,需要在配置文件(my.cnf)中配置如下信息:
# 开启慢查询日志
slow_query_log=1
# 指定超时时间,按需设置,默认为10,单位为秒
long_query_time=10
2
3
4
5
配置完记得重启 MySQL 服务:
systemctl restart mysqld
或者通过 set 命令进行设置:
set global slow_query_log = 1;
set global long_query_time = 10;
2
3
可以通过以下命令查看慢查询日志存储位置:
show variables like 'slow_query_log_file';
# profiling
show profiles 能够在做 SQL 优化时帮助我们了解时间都耗费到哪里去了。
查看当前 MySQL 是否支持 profile 操作:
select @@have_profiling; -- 输出 YES 表示支持
查看 profile 操作是否开启:
select @@profiling; -- 输出 1 表示开启,如果未开启可以使用 set profiling = 1;
查看每条 SQL 的基本耗时情况:
show profiles;
查看指定 query_id 的 SQL 语句各个阶段的耗时情况:
show profile for query query_id;
如:
show profile for query 88;
查看指定 query_id 的 SQL 语句 CPU 使用情况
show profile cpu for query query_id;
如:
show profile cpu for query 88;
# explain/desc
explain 或 desc 命令可以获取 MySQL 如何执行 select 语句的信息。
语法:
explain select_stmt;
desc select_stmt;
2
3
字段解释:
id:select 查询的序列号,表示查询中执行 select 子句或者是操作表的顺序(id 相同,执行顺序从上到下;id 不同,值越大,越先执行)
select_type:表示 select 的类型
- SIMPLE:简单的 select,不实用 UNION 或者子查询
- PRIMARY:最外层 select
- UNION:第二层,在 select 之后使用了 UNION
- DEPENDENT UNION:UNION 语句中的第二个 select,依赖于外部子查询
- UNION RESULT:UNION 的结果
- SUBQUERY:子查询中的第一个 select
- DEPENDENT SUBQUERY:子查询中的第一个 select,取决于外面的查询
- DERIVED:导出表的 select(FROM 子句的子查询)
table:输出的行所引用的表
partitions:该参数用于记录使用的分区信息,NULL 表示该表不是分区表
type:表示连接类型,性能由好到差的连接类型为 NULL、system、const、eq_ref、ref、range、 index、all
- NULL:意味着 mysql 能在优化阶段分解查询语句,在执行阶段甚至不再需要访问表或者索引
- system/const:当 mysql 能对查询的某部分进行优化并转换成一个常量时,它就会使用这些访问类型
- eq_ref:最多只会有一条匹配结果,一般是通过主键或唯一键索引来访问
- ref:索引访问,它返回匹配某个值的行
- range:范围扫描就是一个有限制的索引扫描。它开始于索引的某个点,返回匹配这个值域的行
- index:全索引扫描
- all:全表扫描
possible_key:显示可能应用在这张表上的索引,一个或多个
key:实际使用的索引,如果为 NULL,则没有使用索引
key_len:表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下, 长度越短越好
ref:显示使用哪个列或常数与 key 一起从表中选择行
rows:MySQL 认为必须要执行查询的行数,在 innodb 引擎的表中,是一个估计值
filtered:表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好
Extra:该列包含 MySQL 解决查询的详细信息
- Distinct:MySQL 发现第 1 个匹配行后,停止为当前的行组合搜索更多的行
- Not exists:MySQL 能够对查询进行 LEFT JOIN 优化,发现 1 个匹配 LEFT JOIN 标准的行后,不再为前面的的行组合在该表内检查更多的行
- range checked for each record (index map: #):MySQL 没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用
- Using filesort:MySQL 需要额外的一次传递,以找出如何按排序顺序检索行
- Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息
- Using temporary:为了解决查询,MySQL 需要创建一个临时表来容纳结果
- Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户端
- Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为 index_merge 联接类型合并索引扫描
- Using index for group-by:类似于访问表的 Using index 方式,Using index for group-by 表示 MySQL 发现了一个索引,可以用来查询 GROUP BY 或 - DISTINCT 查询的所有列,而不要额外搜索硬盘访问实际的表