最近做一些项目接口的优化工作,发现其中涉及到调整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的查询优化器会帮你优化成索引可以识别的形式
不适合创建索引的情况
-
频繁更新的字段
-
数据分布比较均匀的,比如,性别字段
-
表数据量少