目录
一.概念
二.查看SQL执行频率
三.定位低效率执行SQL
定位低效率执行SQL—慢查询日志
操作
定位低效率执行SQL—show processlist
四.explain分析执行计划
字段说明
explain中的id
explain中的select_type
explain中的type
explain中的table
explain中的rows
explain中的key
explain中的extra
在应用的的开发过程中,由于初期数据量小,开发人员写SQL语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多SQL语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的SQL语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化.
MySQL的优化方式有很多,大致我们可以从以下几点来优化MySQL:
MySQL客户端连接成功后,通过show [session/global] status 命令可以查看服务器状态信息。通过查看状态信息可以查看对当前数据库的主要操作类型。
-- 下面的命令显示了当前 session 中所有统计参数的值
show session status like 'Com_______';-- 查看当前会话统计结果
show global status like 'Com_______';-- 查看自数据库上次启动至今提及结果show status like 'Innodb_row_%';-- 查看针对Innodb引擎的统计结果
参数 | 含义 |
Com_select | 执行select操作的次数,一次查询只累加1。 |
Com_insert | 执行INSERT操作的次数,对于批量插入的INSERT 操作,只累加一次。 |
Com_update | 执行UPDATE操作的次数。 |
com_delete | 执行DELETE操作的次数。 |
Innodb_rows_read | select查询返回的行数。 |
Innodb_rows_inserted | 执行INSERT操作插入的行数。 |
lnnodb_rows_updated | 执行UPDATE操作更新的行数。 |
lnnodb_rows_deleted | 执行DELETE操作删除的行数。 |
Connections | 试图连接MySQL服务器的次数。 |
Uptime | 服务器工作时间。 |
Slow_queries | 慢查询的次数。 |
可以通过以下两种方式定位执行效率较低的sQL语句。
-- 查看慢日志配置信息
show variables like '%slow_query_log%';
-- 开启慢日志查询
set global slow_query_log=1;
-- 查看慢日志记录SQL的最低阈值时间
show variables like 'long_query_time%';
-- 修改慢日志记录SQL的最低阈值时间
set global long_query_time=4;
操作
show processlist;
通过以上步骤查询到效率低的SQL语句后,可以通过EXPLAIN命令获取MysQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。
链接:https://pan.baidu.com/s/1uaxnHLdWm-f5iY4zNc-n9g
提取码:1234
use test_optimize;explain select * from user where uid=1;explain select * from user where uname='张飞';
字段 | 含义 |
id | select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。 |
select_type | 表示SELECT的类型,常见的取值有SIMPLE (简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION (UNION中的第二个或者后面的查询语句) 、SUBQUERY(子查询中的第一个SELECT)等 |
table | 输出结果集的表 |
type | 表示表的连接类型,性能由好到差的连接类型为( system .--> const ..…> eq_ref …….ref .…. ref_or_nul.---> index_merge ---> index_subquery -----> range ---- index ---…> all ) |
possible_keys | 表示查询时,可能使用的索引 |
key | 表示实际使用的索引 |
key_len | 索引字段的长度 |
rows | 扫描行的数量 |
extra | 执行情况的说明和描述 |
id字段是select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。id情况有三种:
1、id相同表示加载表的顺序是从上到下
2、id不同 id值越大,优先级越高,越先被执行
3、id有相同也有不同,同时存在,id相同的可以认为是一组,从上往下顺序执行;在所有的组中id值越大,优先级越高
-- 1、id相同表示加载表的顺序是从上到下
explain select * from user u,user_role ur ,`role` r where u.uid =ur.uid and ur.rid =r.rid ;
-- 2、id不同 id值越大,优先级越高,越先被执行
explain select * from role where rid=(select rid from user_role ur where uid=(select uid from user where uname='张飞'));
-- 3、id有相同也有不同,同时存在,id相同的可以认为是一组,从上往下顺序执行;在所有的组中id值越大,优先级越高
explain select * from role r,(select * from user_role ur where ur.uid=(select uid from user where uname='张飞')) t where r.rid =t.rid;
表示SELECT的类型,常见的取值,如下表所示:
select_type | 含义 |
SIMPLE | 简单的select查询,查询中不包含子查询或者UNION |
PRIMARY | 查询中若包含任何复杂的子查询,最外层查询标记为该标识 |
SUBQUERY | 在SELECT或 WHERE列表中包含了子查询 |
DERIVED | 在FROM列表中包含的子查询,被标记为DERIVED(衍生)MYSQL会递归执行这些子查询,把结果放在临时表中 |
UNION | 若第二个SELECT出现在UNION之后,则标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED |
UNION RESULT | 从UNION表获取结果的SELECT |
连表查询也是simple
-- derived :在from中包含子查询,被标记为衍生表
explain select * from (select * from user limit 2) t;
type显示的是访问类型,是较为重要的一个指标,可取值为:
type | 含义 |
NULL | MySQL不访问任何表,索引,直接返回结果 |
system | 系统表,少量数据,往往不需要进行磁盘lO;如果是5.7及以上版本的话就不是system了,而是all,即使只有一条记录 |
const | 命中主键(primary key)或者唯一(unique)索引;被连接的部分是一个常量(const)值; |
eq_ref | 对于前表的每一行,后表只有一行被扫描。(1) join查询;(2)命中主键(primary key)或者非空唯一(unique not null)索引;(3)等值连接; |
ref | 非唯一性索引扫描,返回匹配某个单独值的所有行。对于前表的每一行(row),后表可能有多于一行的数据被扫描。 |
range | 只检索给定返回的行,使用一个索引来选择行。where之后出现 between ,< , > , in等操作。 |
index | 需要扫描索引上的全部数据。 |
all | 全表扫描,此时id上无索引 |
结果值从最好到最坏以此是: system > const > eq_ref > ref > range > index >ALL
-- explain
-- all
explain select * from user;
-- null 不访问任何表,任何索引,直接返回结果
explain select now();
-- system 查询系统表,表示直接从内存读取数据,不会从磁盘读取,但是5.7及以上版本不再显示system,直接显示all
explain select * from mysql.tables_priv tp ;
-- const
explain select * from user where uid=2;
explain select * from user where uname='张飞';-- 在没有创建唯一索引之前type为all,创建唯一索引之后为const,创建普通索引为refcreate unique index index_uname on user (uname);-- 创建唯一索引
drop index index_uname on user;-- 删除索引create index index_uname on user (uname);-- 创建普通索引
系统表指系统自带的表
注:
eq_ref指左表有主键,而且左表的每一行和右表的每一行刚好匹配
显示这—步所访问数据库中表名称有时不是真实的表名字,可能是简称,
扫描行的数量
列类型 | key_len | 备注 |
id int | key_len = 4+1= 5 | 允许NULL,加1-byte |
id int not null | key_len = 4 | 不允许NULL |
user char(30) utf8 | key_len =30*3+1 | 允许NULL |
user varchar(30) notnull utf8 | key_len =30*3+2 | 动态列类型,加2-bytes |
user varchar(30) utf8 | key_len =30*3+2+1 | 动态列类型,加2-bytes ;允许NULL,再加1-byte |
detail text(10) utf8 | key_len =30*3+2+1 | TEXT列截取部分,被视为动态列类型,加2-bytes ;且允许NULL |
其他的额外的执行计划信息,在该列展示。
extra | 含义 |
using filesort | 说明mysq|会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,称为“文件排序" ,效率低。 |
using temporary | 需要建立临时表(temporary table)来暂存中间结果,常见于order by和group by;效率低 |
using index | SQL所需要返回的所有列数据均在一棵索引树上,避免访问表的数据行,效率不错。 |
using where | 在查找使用索引的情况下,需要回表去查询所需的数据 |
using index condition | 查找使用了索引,但是需要回表查询数据 |
using index;using where | 查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据 |