mysql索引

索引分类

1.单列索引:即一个索引只包含单个列,一个表可以有多个单列索引

2.唯一索引:索引列的值必须唯一,但允许有空值

3.复合索引:即一个索引包含多个列

 

创建、查看、删除、修改索引

创建索引

create index idx_city_name on city(name);

create index idx_city_name_email_status on city(name,email,status);

查看索引

show index from city;

删除索引

drop index idx_city_name on city;

alter命令

alter table city add primary key(id) 添加主键索引

alter table city add unique idx_city_name(name) 创建唯一索引

alter table city add index idx_city_name(name) 添加普通索引,索引值可以出现多次

alter table city add fulltext idx_city_name(name) 指定索引为fulltext,用于全文索引

 

explian 分析语句

1、id select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。

2、select_type 表示select的类型

simple(简单表,既不使用表连接或者子查询)

primary(查询中若包含任何复杂的子查询,最外层查询标记为该标识)

subquery(在select或where列表中包含了子查询)

derived(在from列表中包含了子查询,被标记为derived(衍生)mysql会递归执行这些子查询, 把结果放在临时表中)

UNION(若第二个select出现在union之后,则标记为union;若union包含在from子句的子查询中,外层select将被标记为:derived)

union result (从union表获取结果的select)

3、table 输出结果集的表

4、type 表示表的连接类型,性能由好到差的连接类型为(system—>const—->eq_ref—->ref—->ref_or_null—>index_merge—>index_subquery—>range—>index—>all)

null mysql不访问任何表,索引,直接返回结果

system 表只有一行记录(等于系统表),这是const类型的特列,一般不会出现

const 表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,mysql就能将该查询转换为一个常量。const于将“主键”或“唯一”索引的所有部分与常量值进行比较

eq_ref 类似ref,区别在于使用的是唯一索引,使用主键的关联查询,关联查询出的记录只有一条。常见于主键或唯一索引扫描

ref 非唯一索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,返回所有匹配某个单独值的所有行(多个)

range 值检索给定返回的行,使用一个索引来选择行。where之后出现between,<,>,in等操作。

index index与all的区别为index类型只是遍历了索引树,通常比ALL快,ALL是遍历数据文件。

all 将遍历全表以找到匹配的行

5、possible_keys* 表示查询的时候,可能使用的索引

6、key 表示实际使用的索引

7、key_len索引字段的长度

8、rows 扫描行的数量

9、extra 执行情况的说明和描述

using-filesort 说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,称为“文件排序”

using temporary 使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于order by 和group by

using index 表示相应的select操作使用了覆盖索引,避免访问表的数据行,效率不错。

 

show profile 分析sql

mysql从5.0.37版本开始增加对show profiles和show profile语句的支持。show profiles能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。

select @@have_profiling;

通过have_profiling参数,能够看到当前MYSQL是否支持profile:

select @@profiling;查看是否开启

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

set profiling =1;开启profiling开关;

show profiles;查看sql

show profilie for query 1;分析id为1的sql

sending data状态表示mysql线程开始访问数据行并把结果返回给客户端,而不仅仅是返回给客户端。由于在sending data状态下,mysql线程往往需要做大量的磁盘读取操作,所以经常是整个查询中耗时最长的状态。

show profilie cup for query 1;

1.status sql语句执行的状态

2.duration sql执行过程中每一个步骤的耗时

3.cpu_user

4.cpu_system

 

trace分析优化器执行计划

mysql5.6提供了对SQL的跟踪trace,通过trace文件能够进一步了解为什么哟花钱选择A计划而不是B计划。

打开trace,设置格式为JSON,并设置trace最大能够使用的内存大小,避免解析过程中因为默认内存过小而不能够完整展示。


set optimizer_trace="enabled=on",end_markers_in_json=on;
set optimizer_trace_max_mem_size=1000000;

执行sql语句


select * from A where age < 5

最后检查information_schema.optimizer_trace就可以知道mysql是如何执行SQL的


select * from information_schema.optimizer_trace\G;

 

复合索引索引失效

1.不满足最左匹配原则

2.范围索引列没有放在最后(这里的最后是说复合索引的最后,不是where条件的最后)

3.使用了select *

4.索引列上有计算

5.索引列上使用了函数

6.字符类型没加引号,底层在隐式转换

7.用is null和is not null没注意字段是否允许为空

如果字段不允许为空,则is null 和 is not null这两种情况索引都会失效。

如果字段允许为空,则is null走 ref 类型的索引,而is not null走 range 类型的索引。

8.like查询左边有%

9.使用or关键字 ,如果有一边条件不是索引,那么索引失效,使用union替代

10.not in 在mysql5.7索引会失效,mysql5.8使用range类型索引,外表大而子表小时,IN的效率更高,而外表小,子表大时,EXISTS的效率更高,若两表差不多大,则差不多。

11.<> != 在mysql5.7索引会失效,mysql5.8使用range类型索引 使用大于小于替代不等于

12.mysql 通过索引扫描的行记录数超过全表的10%~30% 左右,优化器也可能不会走索引,自动变成全表扫描。

13.有没有使用索引跟 where 后面的条件有关,而跟 order by 后面的字段没关系 ,而需不需要按文件重排序,则跟 order by 后面的字段有直接关系

 

单列索引和复合索引使用选择

尽量使用复合索引,而少使用单列索引。

创建复合索引


create index idx_name_sta_address on tb_seller(name,status,address);

就相当于创建了三个索引:
   name
   name + status
   name + status +address

创建单列索引


create index idx_seller_name on tb_seller(name);
create index idx_seller_status on tb_seller(status);
create index idx_seller_address on tb_seller(address);

数据库会选择一个最优的索引来使用,并不会使用全部索引。

 

查看索引使用情况

show status like 'handler_read%'; 查看当前会话的索引使用情况

show global status like 'handler_read%'; 查看全局的索引使用情况

 

主键索引上才有数据,其他索引没有数据,只有主键的id。

除了主键索引,其他索引都是保存一个主键的id,然后根据主键的id去主键索引上找数据。

 

索引下推

在mysql5.6之前,复合索引会根据第一个条件找到对应的页,然后把那一页的主键id查出来,根据主键id一次次回表,再把数据全部查出来,然后再进行第二个第三个条件查询。

在mysql5.6之后,引入了索引下推,复合索引会根据第一个条件找到对应的页,然后再根据条件过滤,过滤后的结果,找到对应的主键id,再用主键id找到具体数据。

 

对varchar类型进行建索引的时候,长度可以先用left(列名,n)来计算多次,因为varchar(20)可能有的数据长度为4 有的数据长度为20,没有必要对全部数据进行存储。

 转自:https://www.cnblogs.com/yexuba/p/16309649.html