索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。
索引的出现是为了提高查询效率,但是实现索引的方式却有很多种,所以这里也就引入了索引模型的概念。可以用于提高读写效率的数据结构很多,这里我先介绍三种常见、也比较简单的数据结构,它们分别是哈希表、有序数组和搜索树。
哈希表(hashmap)
哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。put(key,value) “abc” -> 整形数(散列算法) hashcode 55 / 13 余数
哈希表的优点:等值查询非常快
缺点:因为不是有序的,所以哈希索引做区间查询的速度是很慢的。 order by
abc -> hashcode ->100 /13 取余数 = 7 余9
有序数组
有序数组在等值查询和范围查询场景中的性能就都非常优秀。
优点:如果仅仅看查询效率,有序数组就是最好的数据结构了。
缺点:在需要更新数据的时候就麻烦了,往中间插入一个记录就必须得挪动后面所有的记录,成本太高。
二叉搜索树
二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。
想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间,这个查询可真够慢的。
2^0 + 2^1 + 2^2 = 7 100 万
1-3 log 1000000
1-100万 100万
为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。
B树
- 关键字集合分布在整颗树中;
- 任何一个关键字出现且只出现在一个结点中;
- 搜索有可能在非叶子结点结束;
- 其搜索性能等价于在关键字全集内做一次二分查找;
InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。
B+树的形态:
每一个父节点都出现在子节点中,是子节点最大或者最小的值。
B+树相比于b树的查询优势:
-
b+树的中间节点不保存数据,所以磁盘页能容纳更多节点元素,更“矮胖”;
-
b+树查询必须查找到叶子节点,b树只要匹配到即可不用管元素位置,因此b+树查找更稳定(并不慢);
-
对于范围查找来说,b+树只需遍历叶子节点链表即可,b树却需要重复地中序遍历,如下两图:
只有叶子节点包含数据
范围查询:
B+树的特征:
1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。
2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。(链表)
3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
4、B+树查找时是从上到下查找;B-树则是从下往上查找(中序遍历)
B+树的优势:
1.单一节点存储更多的元素(这样该节点下分支变多了,树变矮胖了),使得查询的IO次数更少。
2.所有查询都要查找到叶子节点,查询性能稳定。
3.所有叶子节点形成有序链表,便于范围查询。
基于主键索引和普通索引的查询有什么区别?
如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
如果语句是 select k from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。
1.为什么innodb表必须建主键?
建立主键之后,数据就可以挂在主键的索引下方叶子节点,这样查询起来会很快。如果不建立主键,mysql会选择一列数据不重复的列作为索引列。如果没有找到,那么就会建立隐藏列rowid,这样无形中增加了开销。
2.为什么推荐使用自增主键,而不是字符串。
使用索引时存在大量比对工作,整型比对比字符串比对快。另外存储空间小。
3.为什么不建议mysql单表数据超过2000W?
id为bigint 8字节,指针占6个字节,单个page16K,16 * 1024/14 = 1170
1个page页可以存放数据也可以存放指针 数据1K计算,可以存放16条
所以3层的b+树,第一层放指针,第二层也放指针,第三层放数据 总计 16 * 1170 * 1170 约是2200W,所以如果数据再多,就需要用到4层B+数,这样的查询效率会进一步降低。
,16 * 1024/14 = 1170
1个page页可以存放数据也可以存放指针 数据1K计算,可以存放16条
所以3层的b+树,第一层放指针,第二层也放指针,第三层放数据 总计 16 * 1170 * 1170 约是2200W,所以如果数据再多,就需要用到4层B+数,这样的查询效率会进一步降低。