第一节 统计SQL执行成本

统计SQL的查询成本: last_query_cost
一条SQL查询语句在执行前需要确定查询执行计划,如果存在多种执行计划的话,MySQL会计算每个执行计划所需要的成本,从中选择成本最小的一个作为最终执行的执行计划。
如果我们想要查看某条SQL语句的查询成本,可以在执行完这条SQL语句之后,通过查看当前会话中的last_query_cost变量值来得到当前查询的成本。它通常也是我们评价一个查询的执行效率的一个常用指标。这个查询成本对应的是SQL语句所需要读取的页的数量
SQL查询是一个动态的过程,从页加载的角度来看,我们可以得到以下两点结论:

  1. 位置决定效率。如果页就在数据库缓冲池中,那么效率是最高的,否则还需要从磁盘中进行读取,当然针对单个页的读取来说,如果页存在于内存中,会比在磁盘中读取效率高很多。
  2. 批量决定效率。如果我们从磁盘中对单一页进行随机读,那么效率是很低的(差不多10ms),而采用顺序读取的方式,批量对页进行读取,平均一页的读取效率就会提升很多,甚至要快于单个页面在内存中的随机读取。
    所以说,遇到I/O并不用担心,方法找对了,效率还是很高的。我们首先要考虑数据存放的位置,如果是经常使用的数据就要尽量放到缓冲池中,其次我们可以充分利用磁盘的吞吐能力,一次性批量读取数据,这样单个页的读取效率也就得到了提升。

第二节 分析查询语句:EXPLAIN

2.1 基本语法

如果我们想看看某个查询的执行计划的话,可以在具体的查询语句前边加一个 EXPLAIN ,就像这样:

EXPLAIN SELECT 1;

EXPLAIN 语句输出的各个列的作用如下:

列名 描述
id 在一个大的查询语句中每个SELECT关键字都对应一个 唯一的id
select_type SELECT关键字对应的那个查询的类型
table 表名
partitions 匹配的分区信息
type☆ 针对单表的访问方法
possible_keys 可能用到的索引
key 实际上使用的索引
key_len ☆ 实际使用到的索引长度
ref 当使用索引列等值查询时,与索引列进行等值匹配的对象信息
rows ☆ 预估的需要读取的记录条数
filtered 某个表经过搜索条件过滤后剩余记录条数的百分比
Extra ☆ 一些额外的信息

2.2 详细解释

为了让大家有比较好的体验,下面调整了下 EXPLAIN 输出列的顺序。

2.2.1 table

不论我们的查询语句有多复杂,里边儿包含了多少个表 ,到最后也是需要对每个表进行 单表访问的,所以MySQL规定EXPLAIN语句输出的每条记录都对应着某个单表的访问方法,该条记录的table列代表着该表的表名(有时不是真实的表名字,可能是简称)。

2.2.2 id

我们写的查询语句一般都以 SELECT 关键字开头,比较简单的查询语句里只有一个 SELECT 关键字,比如下边这个查询语句:

SELECT * FROM s1 WHERE key1 = 'a';
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a’;


稍微复杂一点的连接查询中也只有一个 SELECT 关键字,比如:

SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key1 WHERE s1.common_field = 'a';
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2;

mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';

mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key2 FROM s2 WHERE common_field= 'a');


查看mysql优化后的sql:

EXPLAIN EXTENDED SELECT * FROM s1 WHERE key1 IN (SELECT key2 FROM s2 WHERE common_field= 'a');
SHOW WARNINGS;

小结:
id如果相同,可以认为是一组,从上往下顺序执行
在所有组中,id值越大,优先级越高,越先执行
关注点:id号每个号码,表示一次独立的查询, 一个sql的查询次数越少越好

2.2.3 select_type

名称 描述
SIMPLE 简单查询(不使用UNION或子查询)
PRIMARY 最外层的查询
UNION UNION中第二个语句或后面的语句
UNION RESULT UNION每个结果集的取出来后,进行合并操作
dependentSubquery 子查询中的第一个 SELECT,依赖了外面的查询
derived 派生表,子查询在 FROM子句中


SIMPLE
SIMPLE,最简单的查询方式。

EXPLAIN SELECT * FROM `sys_user`

primary、union、union result
PRIMARY,主查询。
UNION,UNION中第二个语句或后面的语句。
UNION RESULT,UNION每个结果集的取出来后,进行合并操作。

EXPLAIN  select * from sys_user where user_id=1
union
select * from sys_user where user_id=2

Subquery
子查询:#如果包含子查询的查询语句不能够转为对应的semi-join(多表连接)的形式,并且该子查询是不相关子查询。#该子查询的第一个SELECT'关键字代表的那个查询的select type '就是SUBQUERY

EXPLAIN SELECT*
FROMcoupon_give_gift
WHEREcoupon_id = ( SELECT coupon_id FROM coupon WHERE id = '111’ );

EXPLAIN SELECT*
FROMcoupon_give_gift
WHEREcoupon_id in ( SELECT coupon_id FROM coupon WHERE id = '111’ );


查询优化器把in换成关联查询

dependentSubquery
DEPENDENT SUBQUERY,子查询中内层的第一个SELECT,依赖于外部查询的结果集。

EXPLAIN SELECT*
FROMcoupon_give_gift
WHEREcoupon_id = (SELECT sub_title FROM coupon WHERE coupon_give_gift.coupon_id = coupon.coupon_id );


derived
DERIVED,派生表,子查询在 FROM子句中。

explain select * from
(
select user_id,count(*) from sys_user
group by user_id
) user1

2.2.4 partitions

EXPLAIN SELECT * FROM user_partitions WHERE id>200;

查询id大于200(200>100,p1分区)的记录,查看执行计划,partitions是p1,符合我们的分区规则。

2.2.5 type

完整的访问方法如下: system , const , eq_ref , ref , fulltext , ref_or_null ,index_merge , unique_subquery , index_subquery , range , index , ALL 。

system : 该表只有一行(相当于系统表),system是const类型的特例
const:当我们根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是`const ’

mysql> EXPLAIN SELECT * FROM interests where interests_id = 'CRDB951AF8FE05641140FA8FC6638A2B62D20210113016’;


eq_ref:#在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则对该被驱动表的访问方法就是eq _ref

EXPLAIN SELECT * FROM coupon c LEFT JOIN coupon_put_rule cpr on c.coupon_id = cpr.id;


ref:当通过普通的二级索引列与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是`ref’,联合索引时只匹配部分字段也为ref。

EXPLAIN SELECT * FROM coupon_store where coupon_id = 'C5BE9A420C9C26F07580DA1EB13D6A28' and store_id = '3570012’;


ref_or_null:当对普通二级索引进行等值匹配查询,该索引列的值也可以是NULL值时,那么对该表的访问方法就是‘ref or null`

EXPLAIN SELECT * FROM coupon where promotion_id = 'C5BE9A420C9C26F07580DA1EB13D6A28' or promotion_id is null;


index_merge:此类型表示使用了索引合并优化,表示一个查询里面用到了多个索引

EXPLAIN SELECT * FROM coupon where promotion_id = 'C5BE9A420C9C26F07580DD6A28' or coupon_id = 'C5BE9A42DA1EB13D6A8';


unique subquery :是针对在一些包含’IN子查询的查询语句中,如果查询优化器决定将IN子查询转换为EXISTS子查询,而且子查询可以使用到主键进行等值匹配的话,那么该子查询执行计划的 type '列的值就是unique_subquery

EXPLAIN SELECT*
FROMcoupon_give_gift
WHEREcoupon_id in (SELECT id FROM coupon WHERE coupon_give_gift.coupon_id = coupon.coupon_id ) or give_quantity = 1;


range:表示使用了范围类型的查询,一般出现在使用了<>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, 货 IN() 之类的字句和常量值作比较时

EXPLAIN SELECT * FROM coupon where coupon_id in ('111','222','333','444')

index:当我们可以使用索引覆盖,但需要扫描全部的索引记录时,该表的访问方法就是index。

EXPLAIN SELECT coupon_id FROM coupon_give_gift where give_coupon_id = '111';

ALL:全表扫描。
上述分析的过程为从上至下,效率一次降低。

2.2.6 possible_keys和key

在EXPLAIN语句输出的执行计划中,possible_keys列表示在某个查询语句中,对某个表执行单表查询时可能用到的索引有哪些。一般查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用。key列表示实际用到的索引有哪些,如果为NULL,则没有使用索引。比方说下边这个查询:

EXPLAIN SELECT coupon_id FROM coupon WHERE coupon_id = '111' and promotion_id = '111’;

EXPLAIN SELECT coupon_id FROM coupon WHERE coupon_id = '111’or  promotion_id = '111';

2.2.7 key_len

实际使用到的索引长度(即:字节数)#帮你检查是否充分的利用上了索引,同一个索引`值越大越好’,主要针对联合索引。

列类型 KEY_LEN 备注
id int key_len = 4+1 int为4bytes,允许为NULL,加1byte(1字节用来记录是否为null)
id bigint not null key_len=8 bigint为8bytes
user char(30) utf8 key_len=30*3+1 utf8每个字符为3bytes,允许为NULL,加1byte
user varchar(30) not null utf8 key_len=30*3+2 utf8每个字符为3bytes,变长数据类型,加2bytes(2字节用来记录实际长度)
user varchar(30) utf8 key_len=30*3+2+1 utf8每个字符为3bytes,允许为NULL,加1byte,变长数据类型,加2bytes
EXPLAIN SELECT * FROM s1 WHERE id = 1;EXPLAIN SELECT * FROM s1 WHERE key2 = 2;EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';EXPLAIN SELECT * FROM s1 WHERE key_part1 = 'a';EXPLAIN SELECT * FROM s1 WHERE key_part1 = 'a' AND key_part2 = 'b';

2.2.8 ref

当使用索引列等值查询时,与索引列进行等值匹配的对象信息。比如只是一个常数或者是某个列。

EXPLAIN SELECT coupon_id FROM coupon WHERE coupon_id = '111';

EXPLAIN SELECT*
FROMcoupon
inner JOINcoupon_give_gift
on coupon_give_gift.coupon_id = coupon.coupon_id;

2.2.9 rows

预估的需要读取的记录条数,值越小越好。

EXPLAIN SELECT * FROM coupon WHERE id < 100;

2.2.10 filtered

某个表经过搜索条件过滤后剩余记录条数的百分比。如果使用的是索引执行的单表扫描,那么计算时需要估计出满足除使用到对应索引的搜索条件外的其他搜索条件的记录有多少条。

EXPLAIN SELECT * FROM coupon WHERE id < 100 and campaign_coupon_code = '202007071120';

2.2.11 Extra

顾名思义,Extra列是用来说明一些额外信息的,包含不适合在其他列中显示但十分重要的额外信息。我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。MySQL提供的额外信息有好几十个,我们就不一个一个介绍了,所以只挑比较重要的额外信息介绍给大家。

  1. No tables used 当查询语句的没有FROM子句时将会提示该额外信息。
EXPLAIN SELECT 1;


2. Impossible where 查询语句的WHERE子句永远为FALSE时将会提示该额外信息

EXPLAIN SELECT * FROM s1 WHERE 1 != 1;


3. Using where 当我们使用全表扫描来执行对某个表的查询,并且该语句的where 子句中有针对该表的搜索条件时,在Extra列中会提示上述额外信息。当使用索引访问来执行对某个表的查询,并且该语句的WHERE子句中有除了该索引包含的列之外的其他搜索条件时,在`Extra '列中也会提示上述额外信息。

EXPLAIN SELECT * FROM coupon WHERE campaign_coupon_code = '111’;
EXPLAIN SELECT * FROM coupon WHERE coupon_id = '111' and campaign_coupon_code = '111’;


4. Using index 当我们查询列表以及搜索条件中只包含属于某个索引的列,也就是在可以使用覆盖索引的情况下,在Extra列将会提示该额外信息。比方说下边这个查询中只需要用到‘coupon_id’而不需要回表操作:

EXPLAIN SELECT coupon_id FROM coupon WHERE coupon_id = '111’;


5. Using index condition 搜索条件中出现了索引列,按最左匹配原则无法匹配上,但是用到了索引下推。

EXPLAIN SELECT * FROM s1 WHERE key_part1 = 'a' AND key_part3 = 'b';


6. Using join buffer 在连接查询执行过程中,当被驱动表不能有效的利用索引加快访问速度,MySQL一般会为其分配一块名叫`join buffer '的内存块来加快查询速度,也就是我们所讲的‘基于块的嵌套循环算法’

EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field = s2.common_field;


7. Using union 表示需要进行索引合并的索引名称,如果出现了’Using union(…)提示,说明准备使用union索引合并的方式执行查询; 出现了Using sort union(…)提示,说明准备使用’sort-Union `索引合并的方式执行查询。

EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' or key3 = 'a';

  1. Using filesort 很多情况下排序操作无法使用到索引,只能在内存中(记录较少的时候)或者磁盘中(记录较多的时候)进行排序,Mysql把这种在内存中或者磁盘上进行排序的方式统称为文件排序(英文名: ‘filesort’)。如果某个查询需要使用文件排序的方式执行查询,就会在执行计划的Extra列中显示’Using filesort `提示。
EXPLAIN SELECT * FROM s1 ORDER BY common_field LIMIT 10;

  1. Using temporary 在许多查询的执行过程中,MySQL可能会借助临时表来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含DISTINCT '、GROUP BY'、‘UNION等子句的查询过程中,如果不能有效利用索引来完成查询,MysQL很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行#计划的‘Extra列将会显示Using temporary`提示。
EXPLAIN SELECT DISTINCT common_field FROM s1;

2.3 扩展

2.3.1 最左匹配原则

最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。
为什么最左匹配:是因为mysql创建联合索引时,首先会对最左边字段排序,也就是第一个字段,然后再在保证第一个字段有序的情况下,再排序第二个字段,以此类推。所以联合索引最左列是绝对有序的,其他字段无序。举个例子:可以把联合索引看成“通讯录”,姓名作为联合索引,姓是第一列,名是第二列,当查找人名时,是先确定这个人姓再根据名确定人。只有名没有姓就查不到。

2.3.2 索引下推

什么是索引下推
索引下推(Index Condition Pushdown,简称ICP),是MySQL5.6版本的新特性,它能减少回表查询次数,提高查询效率。MySQL服务层负责SQL语法解析、生成执行计划等,并调用存储引擎层去执行数据的存储和检索。索引下推的下推其实就是指将部分上层(服务层)负责的事情,交给了下层(引擎层)去处理。

索引下推优化的原理
先来看一下MySQL的大致框架

  1. 不使用ICP索引扫描的过程


    如上图所示:
    storage层:只将满足index key条件的索引记录对应的整行记录取出,返回给server层
    server 层:对返回的数据,使用后面的where条件过滤,直至返回最后一行。

  2. 使用ICP扫码的过程

    如图所示:
    storage层:首先将index key条件满足的索引记录区间确定,然后在索引上使用index filter进行过 滤。将满足的index filter条件的索引记录才去回表取出整行记录返回server层。不满足index filter条件的索引记录丢弃,不回表、也不会返回server层。
    server 层:对返回的数据,使用table filter条件做最后的过滤。

使用前后的成本差别
使用ICP前,存储层多返回了需要被index filter过滤掉的整行记录。使用ICP后,直接就去掉了不满足index filter条件的记录,省去了他们回表和传递到server层的成本。ICP的 加速效果 取决于在存储引擎内通过 ICP筛选 掉的数据的比例。

使用ICP条件
① 只能用于二级索引(secondary index)
② explain显示的执行计划中type值(join 类型)为 range 、ref 、eq_ref 或者 ref_or_null 。
③ 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤。
④ ICP可以用于MyISAM和InnnoDB存储引擎
⑤ MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持。
⑥ 当SQL使用覆盖索引时,不支持ICP优化方法

2.3.2 前缀索引

什么是前缀索引?
前缀索引也叫局部索引,比如给身份证的前 10 位添加索引,类似这种给某列部分信息添加索引的方式叫做前缀索引。
为什么要用前缀索引?
前缀索引能有效减小索引文件的大小,让每个索引页可以保存更多的索引值,从而提高了索引查询的速度。但前缀索引也有它的缺点,不能在 order by 或者 group by 中触发前缀索引,也不能把它们用于覆盖索引。
索引选择性是什么?
  索引的选择性,指的是不重复的索引值(基数)和表记录数的比值。选择性是索引筛选能力的一个指标。索引的取值范围是 0—1 ,当选择性越大,索引价值也就越大。
  举例说明:假如有一张表格,总共有一万行的记录,其中有一个性别列sex,这个列的包含选项就两个:男/女。那么,这个时候,这一列创建索引的话,索引的选择性为万分之二,这时候,在性别这一列创建索引是没有啥意义的。假设个极端情况,列内的数据都是女,那么索引的选择性为万分之一,其效率还不如直接进行全表扫描。如果是主键索引的话,那么选择性为1,索引价值比较大。可以直接根据索引定位到数据。
什么情况下适合使用前缀索引?
当字符串本身可能比较长,而且前几个字符就开始不相同,适合使用前缀索引;相反情况下不适合使用前缀索引,比如,整个字段的长度为 20,索引选择性为 0.9,而我们对前 10 个字符建立前缀索引其选择性也只有 0.5,那么我们需要继续加大前缀字符的长度,但是这个时候前缀索引的优势已经不明显,就没有创建前缀索引的必要了。
索引选择性怎么计算?
首先我们可以通过如下 SQL 得到全列选择性:

SELECT COUNT(DISTINCT column_name) / COUNT(*) FROM table_name;

例如:

SELECT COUNT(DISTINCT coupon_id) / COUNT(*) FROM coupon;

然后再通过如下 SQL 得到某一长度前缀的选择性:

SELECT COUNT(DISTINCT LEFT(column_name, prefix_length)) / COUNT(*) FROM table_name;

例如:

SELECT COUNT(DISTINCT LEFT(coupon_id, 6)) / COUNT(*) FROM coupon;
SELECT COUNT(DISTINCT LEFT(coupon_id, 8)) / COUNT(*) FROM coupon;

MySQL性能分析工具相关推荐

  1. mysql 性能分析_十大MySQL性能分析工具汇总!专治MySQL性能瓶颈

    前言 MySQL 数据库最常见的两个瓶颈是CPU和I/O的瓶颈.CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候,磁盘I/O瓶颈发生在装入数据远大于内存容量的时候. MySQL数据库性能 ...

  2. MySQL性能分析工具的使用:慢查询日志、EXPLAN的使用、分析优化器执行计划:trace、MySQL监控分析视图-sys schema

    文章目录 1.数据库服务器的优化步骤 2.查看系统性能参数 2.1 语法 2.2 常用参数 3.统计SQL的查询成本:last_query_cost 4.定位执行慢的SQL:慢查询日志 4.1 慢查询 ...

  3. mysql性能分析工具soar使用

    目录 soar介绍 安装 windows安装 工具使用 soar介绍 soar是小米开源的一个对 SQL 进行优化和改写的自动化工具. 跨平台支持(支持 Linux, Mac 环境,Windows 环 ...

  4. mysql性能分析工具profiling_Mysql系列(十)—— 性能分析工具profiling

    explain是从mysql怎样解析执行sql的角度分析sql优劣.profiling是从sql执行时资源使用情况的角度来分析sql. 分析SQL执行带来的开销是优化SQL的重要手段.在MySQL数据 ...

  5. MySQL性能分析工具profile使用教程

    分析SQL执行带来的开销是优化SQL的重要手段.在MySQL数据库中,可以通过配置profiling参数来启用SQL剖析.该参数可以在全局和session级别来设置.对于全局级别则作用于整个MySQL ...

  6. 【宋红康 MySQL数据库 】【高级篇】【12】性能分析工具的使用

    持续学习&持续更新中- 学习态度:守破离 [宋红康 MySQL数据库 ][高级篇][12]性能分析工具的使用 数据库服务器的优化步骤 查看系统性能参数 统计SQL的查询成本:last_quer ...

  7. mysql监控和性能分析工具

    mysql监控和性能分析工具 Mysql作为广泛应用的数据库系统,平时运维工作中对她的监控必不可少,现在把我对Mysql数据库的监控体会写成下文,欢迎拍砖. 无论是DBA或是SA,监控的目标都很明确, ...

  8. MySQL系列-高级-性能分析工具-EXPLAIN

    MySQL系列-高级-性能分析工具-EXPLAIN 1. EXPLAIN概述 1.1 官网介绍 1.2 EXPLAIN 基本语法 2. 基于函数和存储过程插入数据 2.1 创建表 2.2 创建函数和过 ...

  9. Mysql进阶优化篇01——四万字详解数据库性能分析工具(深入、全面、详细,收藏备用)

    前 言 ?? 作者简介:,长跑型选手,立志坚持写10年博客,专注于java后端 ?? 专栏简介:mysql进阶,主要讲解mysql数据库进阶知识,包括索引.数据库调优.分库分表等 ?? 文章简介:本文 ...

最新文章

  1. 剑指 Offer 17. 打印从1到最大的n位数
  2. Hadoop 中zoo_0基础如何入门HADOOP
  3. python读取配置文件获取所有键值对_python ConfigParser模块读写配置文件
  4. Laravel核心解读--完结篇 1
  5. oracle sql 匹配 一位,关于在SQL中查找匹配间隔:在SQL中查找匹配间隔-Oracle
  6. SAP License:中国集团管控存在的主要问题-已加入点评
  7. xercesimpl做什么用的_一体化泵站是用来做什么的有什么用
  8. Codeforces Round #701 D. Multiples and Power Differences LCM性质
  9. 【转】如何设置服务器网卡千兆变万兆
  10. Javascript 事件详解
  11. yamaha php mt8评测,诶哟这个盒子不错哟,NUC 8i5BEK简单开箱+评测(更新完毕)
  12. 贝多芬第九交响第五乐章合唱歌词
  13. Linux配置拨号服务器
  14. 盘点2016最值得突击的七大海外市场:最后一年窗口期,不出海就出局!
  15. 33 《对权威的服从:一次逼近人性真相的心理学实验》 -豆瓣评分9.0
  16. 程序员疯传「编程语言鄙视链」,究竟谁能逃过一劫?
  17. Google宣布收购摩托罗拉移动
  18. 谷歌、三星、腾讯...全球上市公司巨头投资了哪些区块链项目?
  19. 95后离职汇智动力,现在月薪9k,哭着说出经历!
  20. mac系统上idea插件下载不下来或安装不上怎么办

热门文章

  1. #2991. kiki君的护盾 (shield)
  2. 微信小程序通过微信群发消息(订阅消息)
  3. 联想拯救者Y700评测 怎么样
  4. 如何高效搜索公众号文章(r11笔记第35天)
  5. 返回ajax有几种方式,java ajax返回 Json 的 几种方式
  6. 用freemarker生成word文档,并插入图片
  7. 58域内路由和域间路由
  8. 密苏里大学理工学院计算机,密苏里大学理工学院
  9. html5 声控游戏,声控最爱的10款声音类APP,有趣又好玩!
  10. 前端面试题及答案(字节跳动)(二)