mysql-索引(2)索引失效情况以及优化细节

索引的使用

本文主要是做笔记用的,所以有些凌乱,不喜勿喷。

一、索引匹配类型

tabA 表的组合索引 a,b,c
a varchar(24) 非空,
b int(11) 非空 ,
c varchar(20) 非空

1 全值匹配
explain select * from tabA where c='cat' and a='tom' and b=1 ;  

下面sql执行计划的索引长度 key_len=140 ,
计算方法:
设计表的时候会有一段字符编码,一般设置为utf-8,占3个字节,gbk 占2个字节,拉丁 占1个字节
(24+20)*3(utf-8 是每个长度由3个字节来存储) +intlength(4)+0(标志位,允许为空的额外长度计算值)+4(varchar类型最终要加2个字节,2个varchar4个字节)=140

2 匹配最左前缀
explain select * from tabA where  a='tom' and b=1 ;

下面sql执行计划的索引长度 key_len=78 ,
计算方法:
设计表的时候会有一段字符编码,一般设置为utf-8,占3个字节,gbk 占2个字节,拉丁 占1个字节
24*3(utf-8 是每个长度由3个字节来存储) +int(4)+2(varchar类型最终要加2个字节 )=78

3 匹配列前缀

1)模糊查询 like ,失效情况 like后面直接加通配符

4 匹配范围查询

1)普通索引或者组合索引第一列用的范围查询,效率也很高,【因为会用到索引,innodb 的b+tree底层叶子会指向相邻叶子地址,是个双向链表,且叶子节点存储有序。】

explain select * from tabA where a>'tom'

2)组合索引用到了范围查询
这里索引长度key_len=78,说明索引只用到了 a,b ; c没有用到,说明组合索引用范围查询时,范围查询列后面的索引列会失效

explain select * from tabA where a='tom' and b>1  and c='cat'

3)只用索引列做查询

explain select a,b,c from tabA where a='tom' and b=1  and c='cat'

执行计划extra = using index 表示索引覆盖,无需回表,效率高。

二、or生效情况和失效情况

1 、or生效情况
tabB表,只有 a,b,c 三个字段,均为int 类型且允许为null ,且为联合索引 a,b,c

explain select * from tabB where a=1 or b=3  ;

适用了联合索引,且key_len=15 ,= 4(int 长度为4)*3(3个int)+3(3个允许为空,每个空占一个字符)。表示索引用到了 a,b,c

explain select * from tabB where a=1  ;  -- 执行计划里 key_len=5

使用and

explain select * from tabB where a=1 and c=4 ;  -- 执行计划里 key_len=5;

explain select * from tabB where a=1 and b=4 ;  -- 执行计划里 key_len=10;

2 or失效情况
tabC表,4个字段 a,b,c,d,且联合索引为 a,b,c
a,b,c均为int类型,d为varchar(10) 类型,均允许为空。

-- 索引失效,执行计划里,没有使用索引。
explain select * from tabC where a=1 or b=3  ;
-- 索引失效 。
explain select * from tabC where a=1 or a=3  ;
explain select * from tabC where a in(1,3)  ;

如果不查询普通列,则用or也不会使索引失效,且key_len=15

explain select a,b,c from tabC where a=1 or b=3  ;  

小结:列全部是组合索引,即便使用or,索引也会生效。
表里除了组合索引的列,还含有其他列
全表扫描的时候,
组合索引 a用in和or都会失效,
a=1 and b>2 and c=1 b后面的c会失效,因为用到了范围查询

索引失效情况:
1 order by a asc, b desc
2 like ‘%ms’ 通配符在前面的,大多数情况会导致索引失效,但不绝对
3 组合索引 a,b,c a=1 and b>2 and c=1, c会失效,因为b用到了范围查询
4 索引列上有函数
5 不满足最左前缀
6 使用不等号
7 隐士类型转换。比如varchar类型,结果写成数字,数据库会自动做类型转换,这个索引字段的索引功能就会失效

三、索引覆盖

1 、tabD ,a主键,b 索引,组合索引(c,d)

EXTRA using index
explain select c,d from tabD\G

2、tabE a主键,b 索引,c 普通列。

EXTRA using index
explain select a,b from tabE where b='123'\G

EXTRA:null
explain select a,c from tabE where b='123'\G

优化细节

1 索引列不要参与计算

比如 a*3=15 这种,可以改为a=15/3 ,或者拿到业务层计算,不要在数据库层面去计算。

2 当需要很长的字符列作为索引的时候,选择创建前缀索引。
A.计算完整列的选择性,使前缀的选择性接近完整列的选择性。
select count(distinct cola)/count(*) from tabF;//得到一个浮点型小数a

B 计算不同前缀长度的选择性
select 
count(distinct left(cola,3))/count(*) as c3,
count(distinct left(cola,4))/count(*) as c4,
count(distinct left(cola,5))/count(*) as c5,
count(distinct left(cola,6))/count(*) as c6,
count(distinct left(cola,7))/count(*) as c7 from tabF;
会有接近a的值,

C.如果数据分布不均匀,只看数据选择性是不够的;
还要看数据重复次数:
select count(*) as cnt,left(city,4) as c4 from tabF group by c4 order by cnt desc limit 5;

D.综上,比如找到了一个合适的索引前缀的长度,创建即可
alter table tabF add key(cola(6));

a. 索引的选择性越高,查询效率越高,唯一索引的选择性是1,是最好的索引,性能也是最好的。
b. 索引的选择性:率重后的索引值和总记录数的比值
c. 对于很长的varchar类型的列,或者blob,text的列,必须使用前缀索引,mysql不允许索引这些列的完整长度。
d:前缀索引缺点:不能group by,order by ,和索引覆盖扫描

3 使用索引来做排序

索引存储的时候就维护数据按顺序存储。
在这里插入图片描述

-- 执行计划key=rental_date   extra:using index conditions
explain select rental_id ,staff_id from rental where rental_date='2005-05-31' order by  inventory_id,customer_id\G

--去掉invetory_id 的时候,key:rental_date ,extra: using index conditions,using filesort【表示用到文件排序】
explain select rental_id ,staff_id from rental where rental_date='2005-05-31' order by  customer_id\G

-- 去掉where条件,索引会失效,加上下面这个where条件,索引生效
explain select rental_id ,staff_id from rental where rental_date='2005-05-31' order by  rental_date,inventory_id,customer_id\G

--- 执行计划key=null   extra:using where ;using filesort  联合索引范围查询,索引失效
explain select rental_id ,staff_id from rental where rental_date>'2005-05-31' order by  rental_date,inventory_id \G

-- 排序一升一降 ,索引失效
explain select rental_id ,staff_id from rental where rental_date='2005-05-31' order by  inventory_id desc ,customer_id asc \G

如果是单列索引,通常情况下,or会使用索引;
如果是组合索引:
a 全部列均为组合索引,会用对应的索引,
b如果部分列是组合索引,那么不会使用索引。
具体是否生效,还是要看实际情况来分析。

4 隐士类型转换也会让索引失效

比如varchar类型,没加单引号,那么执行的时候,会导致该索引列失效。

5 数据更新频繁或者区分度不高的列,不建议创建索引。

基数,率重/总数 超过80% ,可以创建索引。

6 表连接的时候最好不要超过3张表
7 尽量使用limit

limit起到一个限制输出的作用,分页查询只是他的一个附带功能。但是涉及到limit 1000000,5 这种偏移量比较大的,可以替换为使用 in 或者 between and ,或者子查询 或者先投影查询再内联查。

8 单表索引有的书建议控制在6~7个以内

索引过多也会给数据库造成压力,影响性能。

9 单表字段组合索引尽量不要超过5个字段
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值