SQL进入引擎的流程
Eg:select XXX from ….join …on …where ….group by …having …order by …limit
解析顺序:from …on..join … where …group by …having …select …order by .limit
1.1 sql在MySQL服务上的执行流程
参考:www.cnblogs.com/annsshadow/p/5037667.html
dev.mysql.com/doc/refman/5.7/en/memory-use.html
2. 优化工具:
2.1.1. explain 结果参数说明
Eg:优化前SQL:
explain select a.account_id ,a.user_id ,a.course_id
from study_right_logger_11 a join user b on a.user_id = b.user_id
where a.account_id = '60258144' or a.course_id= '124162' ;
备注:study_right_logger_11 建立符合索引顺序:`account_id`, `course_id`, `user_id`
(1).
结果参数 |
参数类型 |
作用 |
含义 |
id |
Id值相同:从上往下顺序执行,数据少的表优先查询 |
Sql中table的执行顺序 |
表的执行顺序因表的行数的变化而改变:笛卡尔积 |
Id值不同越大越优先查询(有子查询时) |
|
|
|
Select_type |
Primary: |
包含子查询SQL的主查询,最外层 |
|
Subquery: |
包含子查询SQL的子查询,非最外层 |
|
|
Simple: |
不包含:子查询和union |
|
|
Derived:衍生查询 |
使用了临时表
|
|
|
Union: |
衍生表,如下图1 |
|
|
Table |
Derived + id(衍生表) |
|
|
|
|
|
|
|
|
|
|
Type |
system |
理想情况,实际达不到。只有一条数据的系统表或衍生表只有一条数据的主查询.eg:select * from ( Select * from test1)t where tid =1; test1中只有一条数据 |
索引类型 |
const |
仅能查到一条数据是SQL 用于primary key 或unique索引 |
结果仅有一条数据 |
|
eq_ref |
唯一性索引,对于每个索引键的查询,返回匹配唯一行数据,有且只有1个不能为0( 如果表中的索引列有没查询出来的数据则认为是0 ,即全部索引列必须全部查询出来,基本很难满足)。 即索引列的每个值都是唯一的,eg:name 全是唯一的,且是索引列 |
结果是多条数据,但每条数据唯一 |
|
ref |
非唯一性索引,对于每个索引键的查询返回匹配的所有行。 |
结果是多条,(0 或者多条) |
|
range |
查询指定范围的行,where后面是一个范围查询(between,< ,> ,in 有时会失效,转为无索引) |
|
|
Index |
查询全部索引数据
|
|
|
all |
查询全部表中的数据,全表扫描 |
|
|
Index_merge |
MySQL5.0之前,一个表一次只能使用一个索引,无法同时使用多个索引分别进行条件扫描。但是从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引分别进行条件扫描
|
index merge 之intersect
|
|
Possible_keys |
具体索引列 |
|
表示可能用到的索引,是一种预测 |
|
Null |
没有使用索引 |
|
key |
|
|
实际使用到的索引 |
|
|
|
|
Key_len |
索引的长度 |
如果长度是0 ,则该索引列未被使用,用于判断符合索引是否完全被使用 ( a,b,c )三个列的符合索引 符合索引如果要使用后面的列的索引则必然前面是索引也要使用 |
Utf-8:1个字符占用3个字节 A.如果列 是char(10 )则该列占3 * 10 B.如果索引字段可以为null,则会使用1个字节用于标识 C.如果类型是varchar 则除了有一位null的标识,还会用2个字节标识可变长度。即最后多出3位 C. int型占用4个字节,索引中只包含了1列,所以,key_len是4
D . |
ref |
Const |
|
当前表所参照的字段 |
|
|
|
|
|
|
|
|
rows |
整数 |
|
通过索引查询到的数据行数 |
|
|
|
|
extra |
(一) Using filesout |
性能消耗很大,SQL需要优化 |
|
Eg:select * from table1 where a1 = XX order by a2 ; 即:using filesout. |
|||
A.对于单索引,如果排序和查询的列是同一个字段则不会出现using filesout ;如果排序和查询不是同一个字段,则需要额外查询,则是using filesout |
|
|
|
B.复合索引:不能跨列 |
|||
Eg:( a1,a2,a3)复合索引列 Select * from table where a1=XX order by a3; a1跟a3跨列了, Select * from table where a2=XX order by a3; a1被跨了,同样是using filesout |
|||
|
Where 和orderby 按照复合索引的顺序使用,不要跨列 |
||
|
(二) Using temporary:同样性能损耗很大,用到了临时表,常出现在group by Eg:select a1 from table where a1 in( 1,2,3 ) group by a2; 查询的a1 但是根据a2分组,会导致MySQL再创建临时表查询结果 则extra 就是Using temporary,所以要查询和排序列一致 注:解析过程 From..on..join..where..group by..having..select distinct ..orderby limit… Eg:select * from table where a2=2 and a4=4 group by a2,a4 ;--没有using temporary
Select * from table where a2 =2 and a4=4 group by a3;using temporary
|
||
|
(三) Using index :性能提升的标识—索引覆盖 说明当前的SQL不读取原文件,只从索引文件获取数据,不需要回表查询 只要查询的列全部都在索引中就会是using index Eg:复合索引( a1, a2,a3 ) Select a1,a2 from table where a1 =XX and a2=XXX 上面的SQL就会使用using index
|
||
|
(四) Using where :需要回表查询 Eg:a1 是索引列 Select a1,a2 from table where a1=XX 上面是SQL必须回原表查询a2
也有特殊情况,MySQL底层的优化器也会帮助优化SQL语句 Eg:复合索引:a1,a2,a3 Select a1,a2,a3 from table where a2=X and a1=x and a3=xx; 上面虽然跟复合索引顺序不一致,但也是using index 是因为SQL优化器的结果
Eg:复合索引:a1,a2,a3 Select a1,a2,a3 from table where a1=1 and a3=3 order by a2; 结果是:Using index + Using where A1在索引中可以直接查询,但a3无效因为跨列了,则需要回表查询(using where )
|
||
|
五. using index condition:查找使用了索引,但是需要回表查询数据
|
||
|
六. using intersect:表示使用and的各个索引的条件时,该信息表示是从处理结果获取交集 using union:表示使用or连接各个使用索引的条件时,该信息表示从处理结果获取并集 using sort_union和using sort_intersection:与前面两个对应的类似,只是他们是出现在用and和or查询信息量大时,先查询主键,然后进行排序合并后,才能读取记录并返回。 |
||
|
七.using join buffer: mysql 引擎使用了连接缓存,说明SQL质量很差
|
||
|
|
从 mysql5.0.3版本以后才开放的。但是在mysql5.7之后,profile信息将逐渐被废弃,mysql推荐使用performance schema
2.2.1. 开启使用
可以定位SQL执行过程中对CPU和io的消耗
(1)方法一
A.查看是否启用:SELECT @@profiling;
开启profile :SET profiling = 1; //临时打开,而不是全局打开
当打开后,所有的SQL语句全部记录
B. 查看记录 :query :show profile for query 1; // 数字表示查询的ID
备注:在使用profile查看执行过程记录之前要先把profile关闭掉,即:
SET profiling = 0;
C. show profile cpu,block io,memory,swaps for query 查询ID;
D.用show profiles;可以查询之前操作SQL对应的ID值
缺点:消耗性能,在生产环境是关闭的
(2)方法二:查询全局日志,记录了开启后的全部SQL日志
查看命令:show variables like '%general_log%';
打开全局日志命令:set global general_log=1; 或等2
文件会记录:mysql.general_log ( mysql 库的general_log 表 )
2.2.2 查询参数
备注:使用select @@ mysql的配置参数名称,就可以查询出该参数对应的具体值
Eg:
如果IO的in和out 都是0 说明数据都已经被缓存在内存中了。
2.3.1. 介绍
A.MySQL的performance schema 用于监控MySQL运行过程中的资源消耗、资源等待等情况。主要关注数据库运行过程中的性能相关的数据,与information_schema不同,information_schema主要关注server运行过程中的元数据信息
B.提供了一种在数据库运行时实时检查server的内部执行情况的方法。performance_schema 数据库中的表使用performance_schema存储引擎。该数据库主要关注数据库运行过程中的性能相关的数据
C.对server内部活动中所做的任何事情以及对应的时间消耗
D.performance_schema中的事件只记录在本地server的performance_schema中,其下的 这些表中数据发生变化时不会被写入binlog中,也不会通过复制机制被复制到其他server中
E.performance_schema的表中的数据不会持久化存储在磁盘中,而是保存在内存中,一旦服务器重启,这些数据会丢失
2.3.2. 使用介绍
2.3.2.1.查询当前MySQL的实例是否支持,
命令:show engines;
2.3.2.2.performance_schema被视为存储引擎
查看是否支持命令:
SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE ='PERFORMANCE_SCHEMA';
2.3.2.3.启用方法
performance_schema在5.7.x及其以上版本中默认启用(5.6.x及其以下版本默认关闭),如果要显式启用或关闭时,我们需要使用参数performance_schema=ON|OFF设置,并在my.cnf中进行配置:
[mysqld]
performance_schema = ON # 注意:该参数为只读参数,需要在实例启动之前设置才生效
2.3.2.4.查询是否开启,
命令:SHOW VARIABLES LIKE 'performance_schema';
2.3.2.5.查询引擎涉及到的所有表:
performance_schema引擎相关的元数据来了解在performance_schema下存在着哪些表:
命令:SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA ='performance_schema' and engine='performance_schema';
2.3.3. performance_schema表的分类
performance_schema库下的表可以按照监视不同的纬度进行了分组,例如:或按照不同数据库对象进行分组,或按照不同的事件类型进行分组,或在按照事件类型分组之后,再进一步按照帐号、主机、程序、线程、用户等
2.3.3.1. 事务相关
事务事件记录表,记录事务相关的事件的表,与语句事件类型的相关记录表类似:
A.查询语句:show tables like 'events_transaction%';
B.作用:
2.3.3.2.内存相关
A.查询语句: show tables like 'events_transaction%';
2.3.3.3. 等待事件记录相关
A.查询语句:show tables like 'events_wait%';
+-----------------------------------------------+
| Tables_in_performance_schema (%wait%) |
+-----------------------------------------------+
| events_waits_current |
| events_waits_history |
| events_waits_history_long |
| events_waits_summary_by_account_by_event_name |
| events_waits_summary_by_host_by_event_name |
| events_waits_summary_by_instance |
| events_waits_summary_by_thread_by_event_name |
| events_waits_summary_by_user_by_event_name |
| events_waits_summary_global_by_event_name
2.3.3.4. 阶段事件记录相关
A.查询语句:show tables like 'events_stage%';
都是events_stages_* 开头的表
2.3.4. 运行时配置
2.3.4.1. 开启配置
A.在引擎启动时并非所有表instruments(事件采集项,在采集项的配置表中每一项都有一个开关字段YES和NO)和consumers(与采集项类似, YES就表示对应的表保存性能数据,为NO就表示对应的表不保存性能数据)都启用了。需要手动开启收集配置。
B.打开等待事件的采集器配置项开关,需要修改setup_instruments 配置表中对应的采集器配置项
开启语句:UPDATE setup_instruments SET ENABLED = 'YES', TIMED = 'YES' where name like 'wait%';
C.打开等待事件的保存表配置开关,修改修改setup_consumers 配置表
开启语句:UPDATE setup_consumers SET ENABLED = 'YES' where name like '%wait%';
D.其他事件都类似
2.3.5. 应用:监控查询例子
2.3.5.1.查询连接数据库实例的线程连接数量及账号
select * from performance_schema.accounts;
2.3.5.2.查询SQL执行时长的历史记录
SELECT EVENT_ID, TRUNCATE(TIMER_WAIT/1000000000000,6) as Duration, SQL_TEXT FROM performance_schema.events_statements_current where SQL_TEXT IS NOT NULL AND SQL_TEXT <> 'BEGIN';