1. 索引简介
索引是帮助MySql高效获取数据的排好序的数据结构
在数据量大的时候,索引可以大大提高MySQL的检索速度
索引实际也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的
虽然索引大大提高了查询效率,同时却也降低更新表的速度
2. MySql索引的数据结构
实现索引的数据结构:二叉树、红黑树、Hash表、B+tree
最开始的索引的实现是二叉树,后来慢慢改进,到现在MySql的索引只有俩种实现方式,Hash表和B+Tree,但Hash表不常用
为什么mysql索引不采用红黑树而采用b树?
首先要知道数据库索引是存储在外部磁盘上的
当利用索引查询的时候,不可能把整个索引全部加载到内存,只能逐一加载每个磁盘页,磁盘页对应索引树的节点
那么Mysql衡量查询效率的标准就是磁盘IO次数。
如果使用二叉树作为索引结构,那么磁盘的IO次数和索引树的高度是相关的
因为当数据量过大时,使用红黑树树的高度会很高,所以对硬盘的读取次数会比较多,时间就比较慢
二叉树:右边子节点存储大于父节点
红黑树:红黑树和平衡二叉树(左右两个子树的高度差不超过1)比较像,节点是红色或黑色,根节点是黑色,叶子节点都是黑色的空节点
(1) Hash表
来自诸葛老师视频的图
Hash表的查询流程:
① 通过hash算法计算散列值,然后将散列值存储到一个数组(哈希桶)中
② 将数据(表的数据)和对应硬盘存储地址存储到链表中
③ 查找时通过散列值找到对应数组(哈希桶)位置,遍历链表,找到查找的数据后取出存储地址,从而去到硬盘中定位这一行数据
Hash不常使用的原因:
hash冲突,不支持范围查询(主要原因) 比如<,>运算符
(2) B+Tree(B+树)
在了解B+Tree前,要先知道B Tree(B树)
B树:
B树和平衡二叉树 的差别就是 B树 属于多叉树,又名平衡多路查找树,即一个结点的查找路径不止左、右两个,而是有多个
数据库索引技术里大量使用B树和B+树的数据结构,一个结点存储多个值(索引)
data是数据在硬盘上的存储地址,也就是数据文件在磁盘上的物理地址
来自诸葛老师视频的图
节点储存的索引数量可以设置,下例图是2个索引(3条路径)
B+Tree(在b树上做了优化得到的)
B+Tree和BTree的区别:
① 非叶子节点只存储索引 (为了更多的存储索引 mysql设置了16kb搬到内存上去的空间大小)
② 有索引重复(冗余) 比如下例14 20 49 都有重复
③ 叶子节点用指针连接,可以实现区间(同层)访问 利用这一点也实现了范围查询 (比如下图要查找20<col<50,那么直接定位20和50,取中间的就是结果)
索引的定位查找采用二分查找法
推荐一个数据结构可视化测试网站,可以对数据结构进行测试https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
MySql会将要插入B+Tree中的索引先排好序,再插入,因为叶子节点排好序这一点特性才能实现范围查询
3. 索引的分类
(1) 主键索引 (PRIMARY KEY)
主键不可重复,只能有一个列作为主键
(2) 唯一索引 (UNIQUE KEY)
列中的数据不可重复,但多个列都可以作为唯一索引
(3) 常规索引(KEY/INDEX)
默认使用 index 或 key 关键字来创建
(4) 全文索引(FULLTEXT)
在特点的数据库引擎下才有,例如MyISAM
用于快速定位数据
4. 创建索引的语法
(1) 创建单个索引的语法:CREATE INDEX 索引名 on 表名(字段名)
(2) 创建联合索引的语法:CREATE INDEX 索引名 on 表名(字段名1,字段名2)
补充:为什么加入索引能提高查询速度?
例如以下这个这个表,当不添加索引时,需要挨个查找,而因为数据是存储在磁盘上的,每查找一次,也就是读取一次,就会对磁盘做一次IO操作,所以速度会很慢
比如select from t where t.Col2 = 89,就会挨行去查找每一行数据,然后获取Col2去和89进行对比,才能拿到数据
而如果采用索引 (最早期的索引是使用的二叉树,这里以右边的二叉树为例) ,在建立索引的时候,会将Col值存储到一棵二叉树上,每一个节点都会存储一个<key,value> value即是对于的存储地址(磁盘文件地址) 比如34就是0x07 89是0x77
使用索引查询时,从根节点查找,我们都知道对于二叉树的存储,右边子节点存储大于父节点,所以查询的时候,从根节点34出发,因为89>34,所以走右边的节点,发现下一个节点值是89,进行对比89=89成立,就能获取对应的key(存储地址),通过该key就可以直接定位磁盘中的存储地址,获取到数据
5. 联合索引
最左前缀原则
如果创建了(a, b, c)的联合索引,那么其实相当于创建了(a)、(a,b)、(a,b,c)三个索引,在索引查找的时候,总是会先对比最左边的,再依次往右,这被称为最左前缀原则
以下图和对应的sql查询语句来理解该原则
如果使用以下的sql查询语句
① select * from employees where name = 'Bili' and age = 31;
此时会先根据name索引去定位Bili,然后再通过age去定位31
② select * from employee where age = 30 and position = 'dev';
此时不会通过索引去查找数据,因为where后面只有根据age和position去查找,相当于是通过(age,position)去查找
而创建联合索引的时候,第一个值是name,相当于创建的是(name),(name,age),(name,age,position)这三个索引
所以不存在(age,position)这样一个索引,就只能通过普通的逐行查找,这也就体现了最左前缀原则
6. MySql数据库索引存储引擎
(1) myisarm
特点:数据和Index分开存储,即存放在不同文件(非聚集索引),已经过时
查询流程:通过index存储的存储地址(value data)从而去硬盘对应数据的存储地址找到数据
(2) innodb :数据(字段)、data(value 存储地址)、Index(索引)存放在一个文件内(聚集索引)
查询流程就是B+Tree的查询方式,由于数据和Index、data绑定在一起,所以不需要再额外的使用对硬盘IO操作,比myisarm更快,也更常用
为什么推荐使用整形的自增主键?
因为如果不自增,在增加索引的时候,插入到现有的B+Tree中,可能会导致B+Tree变动很大,比如叶子节点容量分裂,根节点增加元素等来达到树平衡,比较耗时
而采用自增永远是在叶子节点的右方开辟新的存储索引的容量空间
B+树相比B树的优势
- 单一节点存储更多的元素,使得查询的IO次数更少;
- 所有查询都要查找到叶子节点,查询性能稳定;
- 所有叶子节点形成有序链表,便于范围查询。
innodb和myisam的区别可以看这篇博文
mysql中innodb和myisam对比及索引原理区别