详细的描述了MySQL中的索引的性能分析。

索引创建的语法

创建索引

CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name ( index_col_name … ) ;

查看索引

SHOW INDEX FROM table_name ;

删除索引

DROP INDEX index_name ON table_name ;

性能分析

SQL执行频次

MySQL客户端连接成功后,通过show [session] global status 命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次:
SHOW GLOBAL STATUS LIKE ‘Com__‘;
注:Com后面六个下划线即为INSERT、UPDATE、DELETE、SELECTINSERT、UPDATE、DELETE、SELECT等单词的长度。

慢查询日志

慢查询日志记录了所有执行时间超过指定参数 (long_query_time,单位:秒,默认10秒) 的所有SQL语句的日志。

MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件 (/etc/my.cnf) 中配置如下信息:

开启MySQL慢日志查询开关

slow_query_log=1

设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志

long_query_time=2

配置完毕之后,通过以下指令重新启动MySQL服务器进行测试,查看慢日志文件中记录的信息/var/lib/mysql/localhost-slow.log

profile详情

show profiles能够在做SQL优化时帮助我们了解时间的具体耗费。通过have_profiling参数,能够看到当前MySQL是否支持profile操作

SELECT @@have_profiling;

默认profiling是关闭的,可以通过set语句在session/global级别开启profiling

SET profiling = 1;

(重要!!!)explain执行计划

EXPLAIN 或者 DESC 命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

语法:

直接在select语句之前加上关键字explain / desc

EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

explain执行计划中包含的信息如下:

  • id: 查询序列号
  • select_type: 查询类型
  • table: 表名或者别名
  • partitions: 匹配的分区
  • type: 访问类型
  • possible_keys: 可能用到的索引
  • key: 实际用到的索引
  • key_len: 索引长度
  • ref: 与索引比较的列
  • rows: 估算的行数
  • filtered: 按表条件筛选的行百分比
  • Extra: 额外信息

一、id列

select查询的序列号(一组数字),表示查询中执行select子句或者操作表的顺序。
id列分为三种情况:

  1. 如果id相同,那么执行顺序从上到下
  2. 如果id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
  3. id相同和不同的,同时存在,同时满足以上两种规则即可。

二、select_type列

复制代码主要用来分辨查询的类型,是普通查询还是联合查询还是子查询

  1. sample: 简单的查询,不包含子查询和union
  2. primary: 查询中若包含任何复杂的子查询,最外层查询则被标记为Primary
  3. union: 在union,union all和子查询中的第二个和随后的select被标记为union
  4. dependent union: 在包含UNION或者UNION ALL的大查询中,如果各个小查询都依赖于外层查询的话,那除了最左边的那个小查询之外,其余的小查询的select_type的值就是DEPENDENT UNION。
  5. union result: 从union表获取结果的select。
  6. subquery: 在select或者where列表中包含子查询(不在from子句中)
  7. dependent subquery: 子查询中的第一个select(不在from子句中),而且取决于外面的查询。
  8. derived: 在FROM列表中包含的子查询被标记为DERIVED,也叫做派生类
  9. UNCACHEABLE SUBQUERY:一个子查询的结果不能被缓存,必须重新评估外链接的第一行对于外层的主表,子查询不可被物化,每次都需要计算(耗时操作)
  10. uncacheable union: 表示union的查询结果不能被缓存:没找到具体的sql语句验证

三、table列

对应行正在访问哪一个表,表名或者别名,可能是临时表或者union合并结果集.

  1. 如果是具体的表名,则表明从实际的物理表中获取数据,当然也可以是表的别名.
  2. 表名是derivedN的形式,表示使用了id为N的查询产生的衍生表.
  3. 当有union result的时候,表名是union n1,n2等的形式,n1,n2表示参与union的id.

四,type列

type是访问类型,访问类型表示以何种方式去访问我们的数据,
访问类型很多,效率从最好到最坏是:
NULL > system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

  1. all: 全表扫描,需要扫描整张表,从头到尾找到需要的数据行。一般情况下出现这样的sql语句而且数据量比较大的话那么就需要进行优化。

  2. index:全索引扫描这个比all的效率要好,主要有两种情况,一种是当前的查询时覆盖索引,即我们需要的数据在索引中就可以索取,或者是使用了索引进行排序,这样就避免数据的重排序

  3. range:表示利用索引查询的时候限制了范围,在指定范围内进行查询,这样避免了index的全索引扫描,适用的操作符:=, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN()
  4. index_subquery:利用索引来关联子查询,不再扫描全表但是大多数情况下使用SELECT子查询时,MySQL查询优化器会自动将子查询优化为联表查询,因此 type 不会显示为 index_subquery,而是ref
  5. unique_subquery: 该连接类型类似于index_subquery,使用的是唯一索引。大多数情况下使用SELECT子查询时,MySQL查询优化器会自动将子查询优化为联表查询,因此 type 不会显示为 index_subquery,而是eq_ref
  6. index_merge:在查询过程中需要多个索引组合使用.
  7. ref_or_null:对于某个字段即需要关联条件,也需要null值的情况下,查询优化器会选择这种访问方式.
  8. ref:使用了非唯一性索引进行数据的查找
  9. eq_ref :当进行等值联表查询使用主键索引或者唯一性非空索引进行数据查找(实际上唯一索引等值查询type不是eq_ref而是const)
  10. const:最多只能匹配到一条数据,通常使用主键或唯一索引进行等值条件查询
  11. system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,不需要进行磁盘io
  12. NULL:直接显示,例如 SELECT ‘A’ ,一般业务不可能优化为NULL

五、possible_keys列

显示可能应用在这张表中的索引,一个或多个,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

六、key列

实际使用的索引,如果为null,则没有使用索引,查询中若使用了覆盖索引,则该索引和查询的select字段重叠。

七、key_len列

表示索引中使用的字节数,可以通过key_len计算查询中使用的索引长度,在不损失精度的情况下长度越短越好。
索引越大占用存储空间越大,这样io的次数和量就会增加,影响执行效率

八、ref列

显示之前的表在key列记录的索引中查找值所用的列或者常量

九、rows列

根据表的统计信息及索引使用情况,大致估算出找出所需记录需要读取的行数,此参数很重要,直接反应的sql找了多少数据,在完成目的的情况下越少越好。

十、filtered列

针对表中符合某个条件(where子句或者联接条件)的记录数的百分比所做的一个悲观估算。

十一、extra列

包含额外的信息。

  1. using filesort: 说明mysql无法利用索引进行排序,只能利用排序算法进行排序,会消耗额外的资源
  2. using temporary: 建立临时表来保存中间结果,查询完成之后把临时表删除
  3. using index: 这个表示当前的查询是覆盖索引的,直接从索引中读取数据,而不用访问数据表。如果同时出现using where 表名索引被用来执行索引键值的查找,如果没有,表面索引被用来读取数据,而不是真的查找
  4. using where: 使用where进行条件过滤
  5. using join buffer: 使用连接缓存
  6. impossible where:where语句的结果总是false