为什么MySQL数据库索引选择使用B+树
1.前言-介绍各种树
- 二叉查找树:即有序二叉查找树,二叉搜索树;
对于某些情况,二叉查找树会退化成一个有n个节点的线性链;查找效率就很低了;
2.平衡二叉树(AVL): 即带有平衡条件的二叉查找树,一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1,和红黑树相比,它是严格的平衡二叉树;
不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况;
应用:windows NT内核中广泛存在;
红黑树:红黑树确保没有一条路径比其它路径长出两倍;是一种弱平衡二叉树;
1、每个节点非红即黑;
2、根节点是黑的;
3、每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的;
4、如果一个节点是红的,那么它的两儿子都是黑的;
5、对于任意节点而言,其到叶子点树NULL指针的每条路径都包含相同数目的黑节点;
6、每条路径都包含相同的黑节点;
应用:1.C++的STL中的Map和Set;
2.著名的linux进程调度Completely Fair Scheduler, 使用红黑树管理进程控制块的;
3.Nginx中用红黑树管理timer;
4.java中的TreeMap的实现;
2.B/B+树
当大规模数据存储到磁盘中的时候,显然定位是一个非常花费时间的过程,但是我们可以通过B树进行优化,提高磁盘读取时定位的效率。
B/B+树是为了磁盘或其它存储设备而设计的一种==平衡多路查找树;
-
B树(B-树):平衡多路查找树;其与平衡二叉树的区别:
(1) 平衡二叉树节点最多有两个子树,而 B 树每个节点可以有多个子树,M 阶 B 树表示该树每个节点最多有 M 个子树
(2)平衡二叉树每个节点只有一个数据和两个指向孩子的指针,而 B 树每个中间节点有 k-1 个关键字(可以理解为数据)和 k 个子树( **k 介于阶数 M 和 M/2 之间,M/2 向上取整)
(3) B 树的所有叶子节点都在同一层,并且叶子节点只有关键字,指向孩子的指针为 null
(4)和平衡二叉树相同的点在于:B 树的节点数据大小也是按照左小右大,子树与节点的大小比较决定了子树指针所处位置。 -
二叉B树阶M:树中所有孩子结点个数的最大值称为该树的阶:
如:(M=3)
可以看出,B树的每个节点可以表示的信息更多,因此,整个树更加"矮胖";这在从磁盘中查找数据(先读取到内存、后查找)的过程中,可以减少磁盘 IO 的次数,从而提升查找速度。
- B+树性质:
1.节点的子树数和关键字数相同(B 树是关键字数比子树数少一)
2.节点的关键字表示的是子树中的最大数,在子树中同样含有这个数据---->非叶子节点仅用作索引;
3.叶子节点包含了全部数据,同时符合左小右大的顺序; —>叶子节点使用指针连在一起;
非叶子节点相当于是叶子节点的索引(稀疏索引),叶子节点相当于是存储(关键字)数据的数据层;
由于 B+ 树的中间节点不含有实际数据,只有子树的最大数据和子树指针,因此磁盘页中可以容纳更多节点元素,也就是说同样数据情况下,B+ 树会 B 树更加“矮胖”,因此查询效率更快。
B+树的查找必会查到叶子节点,更加稳定;
- B和B+树主要用在文件系统以及数据库做索引,比如MySQL;
n个节点的平衡二叉树的高度为H(即logn);
而n个节点的B/B+树的高度为logt((n+1)/2)+1;
3.为什么B+树比B树更适合数据库的索引?
1.B+树的磁盘IO代价更低:B+树更矮,意味着数据库索引中更少的磁盘I/O操作,更快的速度;
2.B+树的查询效率更加稳定:所有关键字查询的路径长度相同,导致每一个数据的查询效率相当
3.B+树更加适合在区间查询:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,所以B+树更加适合在区间查询的情况;
结论:
数据库索引采用B+树的主要原因是: B树在提高了IO性能的同时并没有解决元素遍历的效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。
4.数据库的索引类型
MYSQL数据库的四种索引类型:普通索引,唯一索引,主键索引与组合索引;
- 1.普通索引:这是最基本的MySQL数据库索引,它没有任何限制。它有以下几种创建方式 :
创建索引:
CREATE INDEX indexName ON mytable(username(length));
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length
修改表结构:
ALTER mytable ADD INDEX [indexName] ON (username(length));
创建表的时候直接指定索引:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) );
删除索引:
DROP INDEX [indexName] ON mytable;
- 2.唯一索引:它与前面的普通索引类似,不同的就是:MySQL数据库索引列的值必须唯一,但允许有空值
创建索引:
CREATE UNIQUE INDEX indexName ON mytable(username(length));
修改表结构:
ALTER mytable ADD UNIQUE [indexName] ON (username(length));
创建表的时候直接指定索引:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );
- 3.主键索引:它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引
创建索引:给表添加主键的时候就创建了主键索引
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) );
- 4.组合索引:
先创建一个多字段的表:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL );
**创建组合索引 **:
ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age);
建立这样的组合索引,其实是相当于分别建立了下面三组组合MySQL数据库索引:
username, city, age
username, city
username