浅学 mysql 中的索引

517 阅读3分钟

最近做一些项目接口的优化工作,发现其中涉及到调整mysql语句的方面,接口速度是提升最高的,借机学习一下关于mysql索引方面的知识

基本是 《高性能MYSQL》的第五章 - 《创建高性能索引》的阅读

之前关于索引的错误理解

  • 建表之后把字段都设置为索引比较好

  • 只要创建了索引并使用这个字段,就能命中索引

索引

索引(在 MySQL 中也叫“键key”)是存储引擎快速找到记录的一种数据结构

所以可以把索引看做一本书的目录

索引的类型

mysql的索引是存储引擎决定的,分为B-tree索引和 哈希索引(hash index)

不同的存储引擎对支持不同的两种索引

ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='xxx表'

我们的项目中,存储引擎是 InnoDB , 它使用的是 B-tree 索引,所以本文只是按照Btree来分享

优点

  • 减少服务器的扫描量

  • 帮助服务器避免排序和临时表

  • 随机IO变为顺序IO

三星原则:一星: 索引将相关的记录放到一起 二星:索引的数据顺序和查找的顺序一致 三星:索引的列包含查询中需要的全部列

创建高性能索引

独立的列

独立的列: 不能是表达式的一部分,也不能是函数的参数

例: 筛选 area 字段是 beijing/beiJing/BeiJing 的数据

area已经在表里添加了索引

select * from TABLE where Upper(area) = 'BEIJING'

如果是用函数处理了area字段

explain  select * from TABLE where Upper(area) = 'BEIJING'

可以看到是无法命中索引的

多列索引

把where中的字段都设置为索引是最好的操作

其实这种情况下,可能达到了一星索引标准,比最优的索引差了很多

所以在需要对多个索引做相交操作(OR)/联合操作(AND) 的时候,可以考虑创建联合索引

多列索引中的顺序

这个是个人感觉比较迷惑的一点,就是创建了联合索引之后,如果sql语句中的字段顺序与定义的不一致,那么有可能也无法使用索引

比如使用id和status定义复合索引

 index (`id`,`status`) 

那么一下几种sql语句 并不是都能使用索引的

select * from T where status = '23'  // 索引失效

select * from T where id > 123 and status = '23'  // 索引部分失效

这个就是索引中的最左匹配原则

最左匹配原则: 索引首先按照最左列进行排序,其次第二列等等。所以索引可按照升序或者降序进行扫描,用以满足符合列顺序的order by / group by等查询需求

  • mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,后面的索引就不再处理,相当于后面的直接失效
如有索引(a, b, c, d),查询条件a = 1 and b = 2 and c > 3 and d = 4,则会在每个节点依次命中a、b、c,无法命中d
  • =和in可以乱序,比如联合索引是 (a,b,c) ,那么 a = 1 and b = 2 and c = 3 可以任意改变顺序 ,因为mysql的查询优化器会帮你优化成索引可以识别的形式

不适合创建索引的情况

  • 频繁更新的字段

  • 数据分布比较均匀的,比如,性别字段

  • 表数据量少