前言:
数据库查询慢的时候,往往想到索引。
索引一般问起来,会考虑他的数据结构的选用,以及B+树的特点~
在mysql中,索引是在存储引擎中实现的。不同的引擎缩印的工作方式是不同的
1.索引常见的数据结构
常见的数据结构包括:哈希表,有序数组和搜索树。
在navicate中以:hash和btree来呈现~
1.1 索引如果选用hash
以K V形式存储,解决冲突方式类似于HashMap,用数组+链表的形式来实现。
hash作为索引,在等值的查询场景中非常优秀。
hash只适合于菲关系型数据库或者Memcached
仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询; (<=>就是mysql中的等于号,但是<=>是mysql特有的,在这里记录一下。)
查询效率很高
1.2 有序数组(在innodb中没有这种索引形式)
等值查询和范围查询都很优秀。
有序的话+二分查找就是很快的处理解决问题的方法~
但是这种有序数组,为什么用的很少?
是因为更新数据的时候很麻烦,中间插入一条数据就需要移动后面所有的数据。
需要很高的成本,所以有序数组索引只适用于静态存储引擎。
后面再也不会修改的东西。
1.3 b树
首先是二叉搜索树的特点:
二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。
为了维持 O(log(N)) 的查询复杂度,你就需要保持这棵树是平衡二叉树;
多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。
在硬盘中查询访问,涉及到操作系统的原理。(寻址时间)
为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。(这也是使用B+树的原因)
MySQL实战45讲 林晓斌中提到:
使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一个 10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。
每一个索引都对应了一个B+树。
1.3.1 主键索引和非主键索引?
根据叶子节点的内容,索引类型分为主键索引和非主键索引。
主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。
1.3.2 使用主键索引好处?回表是什么?
主键查询只需要搜索ID这个树就可以了。但是如果是普通索引,我们必须先搜索这个索引的索引树,然后根据条件找到对应的主键,然后再用主键索引树搜索一次。这个过程叫做回表。
所以尽量使用主键查询。
1.3.3 B+树插入新值的调整过程?
涉及到重点关键字:
页分裂:如果想插入到的数据页已经满了,那么B+树会申请一个新的数据页,移动部分数据过去,这个过程叫做页分裂。
页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%。
页合并:当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。
1.4 索引的选取感悟
能用主键就用主键,需要建立非主键索引的时候,那么尽量保证主键是int或者数字形式。
因为int占了四个字节,而非主键索引树 叶子节点的数据内容是存放了主键。
所以如果主键站的字节很大,会导致非主键索引变大。
适合用业务字段直接做主键的场景:只有一个索引;该索引必须是唯一索引。(也就是不建立其他索引了,直接用业务字段查询条件)
2. 总结
每一张表实际上是N个B+数(因为主键就是一个B+树的存储结构,只不过数据节点是整个行的信息)
查询如果不走索引就是遍历整个索引二叉树。(遍历主键索引)
N叉树的N值在MySQL中是怎么调整?--后面去了解一下
没有主键的表,innodb会给默认创建一个Rowid做主键
索引是为了方便定位到数据页;
很重要!!innodb B+树主键索引的叶子节点存的是页page;一个页可以存多个行!!!
插入数据如果是在某个数据满了页的首尾,为了减少数据移动和页分裂,会先去前后两个页看看是否满了,如果没满会先将数据放到前后两个页上,不知道是不是有这种情况
删除主键的时候其实是重建整张表