MySQL 索引使用笔记

用voucher表来做单表测试

  1. 创建voucher_id为主键

  2. 创建voucher_idx(voucher_id, prefix, voucher_no)

    image.png

当我查主键的时候毫无疑问 肯定是走主键索引的

image.png

当我只查找主键字段的时候 Extra显示“Using index”不回表直接使用到覆盖索引

image.png

可以看到 当查询条件里有主键的时候 查询会直接用主键查询 可能是因为主键是唯一索引 直接就定位到是最简方法

image.png

下面不用主键来做条件, 直接用voucher_idx里的字段来查找

可以看到type变成了ref 不再是有主键时的const

ref:是一种索引访问(有时也叫索引查找),它返回所有匹配某个单个值的行。然而,它可能会找到多个符合条件的行,因此它是查找和扫描的混合体…

可以看到找到了45310条记录,测试的voucher总数是319814  45310/319814≈0.15 不到30%所以还是能使用索引的

image.png

但是这就不对了 prefix是‘A10’的占了76% 还是能用到索引 是不是说明“一个值超过30%就无法使用索引”的描述? 可能是新版功能加强了吧

image.png

这个确实能证实,不是从索引左侧的列搜索用不到索引,这条语句扫描了319814行

image.png

下面这个语句 其实说明了不按索引顺序 也是能用到索引的 应该是索引优化器把where里的索引列又排了下

image.png

查了一下优化器执行的代码 好像也没有对索引重排 看来还是service层做了优化让我们能使用到索引?

image.png

我又创建了一个索引voucher_idx2,我以为搜索条件是voucher_no, prefix和 prefix,voucher_no的时候会不一样,结果都用到了voucher_idx2

image.png

image.png

image.png

这可以说明当查询条件和搜索条件都在索引内时,不按索引顺序也是能用到索引的,但是扫描了全表

image.png

image.png

但是查询列或者搜索列里有不在索引列里的列的时候 是会扫描全表的

image.png

image.png

那我把所有列都拿进来 是不是都能用到索引?? 

image.png 

可以看到,其实是走了索引,但是也是扫了全表,效率应该相当差, 需要用数据量很大的库来试一下,如果不按索引顺序来跑的效率

image.png

MySQL 什么情况下无法使用索引

  1. 通过索引扫描的记录超过30%,变成全表扫描

  2. 联合索引中,第一个索引列使用范围查询

  3. 联合索引中,第一个查询条件不是最左索引列

  4. 模糊查询条件列最左以通配符%开始

  5. 内存表(HEAP)表使用HASH索引时,使用范围检索或者ORDER BY

  6. 两个独立索引,其中一个用于检索,一个用于排序

  7. 使用了不同的ORDER BY 和 GROUP BY 表达式

  8. 索引列检索使用函数 

  9. 两表连接的时候如果连接字段类型不一致是无法使用索引的(其实可以使用,但是需要进行隐式转换,导致没有办法2个表都使用到索引,只有一个表能用到索引,另一个表被隐式转换了 用不到索引 )

2个独立的索引 and的情况下只能用到一个索引,or的情况下可以用到index mearge把结果联合起来

image.png

image.png

image.png

image.png

image.png

image.png

MySQL key_len计算规则

  1. 索引字段的附加信息:可以分为变长和定长数据类型讨论,当索引字段为定长数据类型,比如char,int,datetime,需要有是否为空的标记,这个标记需要占用1字节;对于变长数据类型,比如:varchar,除了是否为空的标记外,还需要有长度信息,需要占用2个字节;

    (备注:当字段定义为非空的时候,是否为空的标记将不占用字节)

  2. 同时还需要考虑表所使用的字符集,不同的字符集,gbk编码的为一个字符2个字节,utf8的一个字符3个字节

总结, key_len的长度计算公式:

image.png

key_len是表示得到结果集所使用的选择的索引的长度,但不包括order by,也就是说,如果order by也使用了索引则ket_len则不计算在内

MySQL Explain

usering index — 覆盖索引

usering filesort — 使用filesort排序算法,对查询结果进行排序(该排序工作无法通过索引的排序直接完成,简而言之,就是要排序的列无索引)

5.6版本以上,才支持EXPLAIN DELETE/UPDATE

MYSQL explain详解

http://blog.csdn.net/zhuxineli/article/details/14455029

MyISAM和 InnoDB 索引对比

image.png

写一个存储过程 随机取10W次 每次一条记录

image.png

image.png

image.png

建议:

  1. InnoDB尽可能通过主键读取记录

  2. InnoDB尽可能设计一个自增长的主键

  3. MyISAM尽可能通过主键或唯一索引读取记录

image.png

MyISAM耗时是InnoDB的1.06倍,InnoDB耗时是MyISAM的94%

这里没有考虑高并发情况下的对比,

因为MyISAM是表级锁 粒度比较大 并发读写

MyISAM只能把索引放到内存里     

InnoDB可以把索引和数据全部放在内存里

28原则,20%的热点数据产生80%的访问

如果把20%的热点数据都放在内存里面,这80%的访问量就会非常快

所InnoDB的优势是非常大的

InnoDB能把索引放到内存里