I 数据库篇
数据库的数据结构
B树
B树也称B-树,它是一颗多路平衡查找树。我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数。当m取2时,就是我们常见的二叉搜索树。
上图:一棵4阶B树。
一颗m阶的B树定义如下:
1)每个结点最多有m-1个关键字。
2)根结点最少可以只有1个关键字。
3)非根结点至少有Math.ceil(m/2)-1个关键字。
4)每个结点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它。
5)所有叶子结点都位于同一层,或者说根结点到每个叶子结点的长度都相同。
B+树
各种资料上B+树的定义各有不同,一种定义方式是关键字个数和孩子结点个数相同。这里我们采取维基百科上所定义的方式,即关键字个数比孩子结点个数小1,这种方式是和B树基本等价的。上图就是一颗阶数为4的B+树。
除此之外B+树还有以下的要求。
1)B+树包含2种类型的结点:内部结点(也称索引结点)和叶子结点。根结点本身即可以是内部结点,也可以是叶子结点。根结点的关键字个数最少可以只有1个。
2)B+树与B树最大的不同是内部结点不保存数据,只用于索引,所有数据(或者说记录)都保存在叶子结点中。
3) m阶B+树表示了内部结点最多有m-1个关键字(或者说内部结点最多有m个子树),阶数m同时限制了叶子结点最多存储m-1个记录。
4)内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。
5)每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序链接。
B树、B+树对比
为什么说B+tree比B 树更适合实际应用中操作系统的文件索引和数据库索引?
-
主要原因:B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低。
-
B+tree的磁盘读写代价更低
B+tree的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点需要2个盘快。而B+树内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B 树就比B+树多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。 -
B+tree的查询效率更加稳定
由于内部结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引,所以,任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当;
数据库索引
索引(Index)是帮助MySQL高效获取数据的数据结构
索引的目的:提高查询效率
原理:通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据。
什么情况下设置了索引但无法使用?
-
以“%(表示任意0个或多个字符)”开头的LIKE语句,模糊匹配;
-
OR语句前后没有同时使用索引;
-
数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型);
-
对于多列索引,必须满足最左匹配原则 (eg:多列索引col1、col2和col3,则 索引生效的情形包括 col1或col1,col2或col1,col2,col3)。
什么样的字段适合创建索引?
- 唯一索引
- 经常作查询选择的字段
- 经常作表连接的字段
- 经常出现在order by, group by, distinct 后面的字段
创建索引时需要注意什么?
- 非空字段
- 取值离散大的字段
- 索引字段越小越好:数据库的数据存储以页为单位,字段小,索引节点就小,一页存储的数据越多,一次IO操作获取的数据越大效率越高。
索引的分类
-
普通索引和唯一性索引:索引列的值的唯一性
-
单个索引和复合索引:索引列所包含的列数
-
顺序索引和散列索引
顺序索引:基于值的顺序排序
散列索引:基于哈希函数,把值平均分布到若干散列桶 -
稠密索引和稀疏索引
稠密索引:搜索码的每个值都有对应索引项
稀疏索引:只有搜索码的某些值有索引。只有索引是聚集索引时才能使用稀疏索引。 -
聚簇索引/主索引与非聚簇索引/辅助索引:
聚簇索引是对磁盘上实际数据重新组织以按指定的一个或多个列的值排序的算法。特点是存储数据的顺序和索引顺序一致。一般情况下主键会默认创建聚簇索引,且一张表只允许存在一个聚簇索引。
非聚集索引的逻辑顺序与磁盘上行的物理存储顺序不同。
聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。聚集索引可以帮助把很大的范围,迅速减小范围。但是查找该记录,就要从这个小范围中Scan了;而非聚集索引是把一个很大的范围,转换成一个小的地图,然后你需要在这个小地图中找你要寻找的信息的位置,最后通过这个位置,再去找你所需要的记录。
唯一索引 vs 主键
唯一索引 › › › 主键
唯一索引:索引列的值必须唯一,但允许有空值。主键是唯一索引,这样说没错;但反过来说,唯一索引也是主键就错误了,因为唯一索引允许空值,主键不允许有空值,所以不能说唯一索引也是主键。
数据库引擎
就是将数据存储到磁盘的接口~MySQL有SQL语句分析层和存储引擎层,当分析出SQL语句需要执行什么操作后,调用存储引擎的接口既可。
MyISAM:非聚集索引
MyISAM引擎使用B+Tree作为索引结构,MyISAM的索引文件仅仅保存数据记录的地址。
MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
InnoDB:聚集索引
InnoDB是默认的MySQL引擎。虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。
- 第一个重大区别是InnoDB的数据文件本身就是索引文件。
MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索 引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB 表数据文件本身就是主索引。 - 第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。
首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全
(transaction-safe (ACID compliant))型表