索引
索引
0.概念
索引,也叫做键(key),是存储引擎用于快速找到记录的一种数据结构。
例如
select s.s_name from student s where s.s_id = 5;
如果在字段s_id上建有索引,则MySQL将使用该索引找到s_id为5的行。也就是说,MySQL先在索引上按值进行查找,然后返回所有包含该值的数据行。
1.数据结构
B-Tree索引:
B-Tree通常意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同。
image-20201023223956661.pngB+Tree索引结构如图
B+Tree的由来
二叉树:需要遍历整个二叉树,查询慢
二叉搜索树:左子树的值都小于根节点,右子树的值都大于根节点。如果插入的顺序有序,则又会退化成链表的形式。
image-20201023224646801.png平衡二叉树(AVL树):在满足二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为1。
image-20201023225544537.png如果在AVL树中插入或删除节点,可能导致AVL树失去平衡,此时AVL树会进行旋转,使之平衡,有四种失去平衡的情况:
image-20201023225734905.png出现不平衡就会旋转,十分耗时。
红黑树:每个节点要么是红色,要么是黑色,根节点必须是黑色的,每个叶子节点是黑色的,红色节点的两个子节点是黑色的,任意节点到每个叶子节点的路径都包含相同数量的黑节点。
红黑树是一种弱平衡二叉树,高度一般高于平衡二叉树,旋转次数小于平衡二叉树。因此:AVL树查找快,删除和插入较慢,红黑树查找慢,删除插入快。
B-Tree:磁盘的io效率非常低,无法一次性将数据加载到内存当中,只能逐一加载磁盘页,每个磁盘页对应一个节点。MySQL默认大小为16k。树的高度决定磁盘的io次数,平衡二叉树的高度较高,导致效率低。
B-Tree不是二叉树,而是一个平衡的多叉树,树的高度低,io次数减少,效率提高。 image-20201023235420940.pngB+Tree:B-Tree的加强版,也是MySQL索引的数据结构。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。提升磁盘io效率。
image-20201023235518703.png
同时,B+Tree的叶子节点通过双向链表相连,更适合于范围查找。
2.作用及规则
B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,而是从索引的根节点开始进行搜索。根节点中存放了指向子节点的指针,存储引擎根据这些指针像下层查找。通过比较节点中的值和要查找的值可以找到合适的指针进入下一层节点,这些指针实际上定义了子节点页中值的上限和下限。叶子节点中的指针指向的是数据。树的深度和表的大小直接相关。
B-Tree对索引列是顺序组织存储的,所以很适合查找范围数据。
有如下数据表:
CREATE TABLE People (
name varchar(50) not null,
dob date not null,
address varchar(200)not null,
gender enum('男','女') not null,
key(name,dob,address)
);
当索引中有多个列时(即联合索引),将按照定义索引时列的顺序排序。例如上表就先按照cardId排序,当cardId相等时再按照name排序。
B-Tree索引适用于全键值、键值范围或键前缀查找。可以使用B-Tree索引的查询类型:
-
全值匹配
全职匹配指的和是索引中的所有列进行匹配。例如上面数据表中的索引可以用于查找名字为Amy,出生于1998-01-01,家乡在内蒙古的人。
-
匹配最左前缀
只使用索引的第一列。例如上面的索引可以用于查找名字为Amy的人。
-
匹配列前缀
只匹配某一列的值的开头部分。例如上面的索引可以用于查找名字A开头的人。
-
匹配范围值
例如上面的索引可以用于查找名字在Amy和Barry之间的人。只使用到了第一列
-
精确匹配某一列并范围匹配另外一列
即第一列全职匹配,第二列范围匹配。例如上面的索引可以用于查找名字为Amy,出生日期在1998-01-01到1999-01-01之间的人。
-
只访问索引的查询
即查询只需要访问索引,而无需访问数据行。
B-Tree索引的限制:
-
如果不是按照索引的最左列开始查找,则无法使用索引
例如上面的索引无法用于查找某个特定生日的人,也无法用于查找某个特定地址的人。因为这两列都不是最左数据列。
-
不能跳过索引中的列
上面的索引无法用于查找名字为Amy且某个特定地址的人。不指定dob,则MySQL无法使用address,只能使用name。
-
如果查询中有某个列的范围查找,则其右边所有列都无法使用索引优化查找
例如有查询WHERE name = 'Amy' AND dob LIKE '%男%' AND address = '内蒙古',这个查询只能使用索引的前两项,因为这里LIKE是一个范围条件。
因为索引树中的节点是有序的,所以除了按值查找外,索引还可以用于查询中的ORDER BY操作。前提是ORDER BY子句满足上面的要求。
索引列的顺序十分重要,在优化性能的时候,可能使用相同的列但顺序不同的索引来满足不同类型的查询需求。
参考:《高性能MySQL第三版》