数据库索引《一》

目录

索引的类型  

回表

索引维护

思考与解答


   索引是存储引擎实现的,没有统一的标准,不同的引擎的索引工作方式不一样。常见的三种索引结构:哈希表/有序数组/搜索树。

哈希表

数据结构:数组+链表的方式;

优点:等值查询的速度比较快; 

缺点:因为无序,做区间查询比较慢,时间复杂度O(N);

适用场景:membercache和noslq等一些存储引擎;                                                  

有序数组

数据结构:数组;

优点:查找和范围查找效率高,二分查找,时间复杂度:O(logN);

缺点:更新数据成本较高,效率低下;

适用场景:静态存储引擎[不需要修改的数据];

N叉树

数据结构: N叉树;

优点:查找和更新的复杂度可以维持在O(logN);

 

跳表 二叉树的原理,“抛硬币法提升一层”
LSM树 LSM 通过将磁盘的随机写转化为顺序写来提高写性能 ,而付出的代价就是牺牲部分读性能、写放大(B+树同样有写放大的问题)。LSM 相比 B+ 树能提高写性能的本质原因是:外存——无论磁盘还是 SSD,其随机读写都要慢于顺序读写

索引的类型  

     我们直到MySql里的默认存储引擎是InnoDB,InnoDB使用了B+树索引模型,所以数据都是存储在B+树中。每一个索引在InnoDB里面对应一棵B+树,每张表由多棵B+树组成。
索引类型分为:主键索引和非主键索引。
  主键索引的叶子节点存的都是整行数据。在InnoDB,主键索引也称为聚簇索引(clustered index);
  非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index);
 下面通过一个实例来具体分析下索引的结构以及是如何工作的。

USER_TABLE | CREATE TABLE `USER_TABLE` (
  `id` int(11) NOT NULL,
  `age` int(11) NOT NULL,
  `orderId` bigint DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `orderId` (`orderId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

//插入数据
insert into students (id, age, orderId) values (1,18,101),(2,19,102),(3,20,103),(4,21,104),(5,22,105);

假设给这张表插入5行数据(id,age,orderId):(1,18,101),(2,19,102),(3,20,103),(4,21,104),(5,22,105)。假设该表的索引是一棵4叉树。

图一:4叉树索引图

回表

下面来看一下:主键索引和普通索引的区别

select * from USER_TABLE where id = 2; 

   主键索引及主键查询方式,我们只需要搜索id这棵B+树,查到的就是整个id=2的行记录; 

select * from USER_TABLE where orderId = 102;

   普通索引查询,我们需要先查询orderId 二级索引,得到id=1,然后再搜索主键索引得到行记录,这里可以看到,我们进行来两次查询,这个过程叫做回表。所以很明显,主键索引只需要搜索一次就可以拿到数据。普通索引先搜索索引拿到主键,然后再到主键索引搜索一次才可以拿到这个值(回表)。我们在实际使用过程中,尽量使用主键索引减少查询次数,提高效率

索引维护

    我们知道B+树在构造的过程中当某个分支的节点数大于N的时候存在分裂和合并的过程。这里涉及到数据的增加和删除,其中增加节点过程中的分页:将会影响性能空间利用率下降,因为需要移动一半的数据到一个新的空间。
    从上面我们可以看出主键索引的重要性,那么自增主键做索引的好处是什么呢?
 性能方面
     一般插入新纪录的时候,我们不需要指定id的值,系统会获取当前的最大的id自增后作为下一条记录id的值。这样的好处是:构造B+ 树过程中,不需要移动大量的数据,不涉及到叶子节点的分裂,性能较高。不是有序的节点的插入往往成本较高。主要的是通过主键做索引无需回表查询,减少磁盘访问次数,提高效率
存储空间
     主键一般都是整型数据,只需要4个字节,如果是长整型需要8个字节。但是如果是业务字段做索引,比如订单号或者省份证号都会比主键大,而主键是二级索引的值,所以二级索引就会占用更大的空间。
    显然主键越小,普通的索引的叶子节点就越小,占用的空间就越小。

   总体来说,我们需要“尽量使用主键来查询”的原则,避免搜索两棵树。

    当然在KV存储场景中:只有一个索引且必须唯一,这个时候使用业务字段直接做主键是十分合适的。

 

思考与解答

问题一:为什么不使用二叉树,要使用N叉树?

答:虽然平衡二叉树的搜索和更新效率很高,但是大多数的数据库并不是采用的二叉树,这是因为索引不只是存在内存中,还要写到磁盘上。仅仅对于1024个数据节点,二叉树的树高达到了10,那么一次查询就需要查询10个数据块。从磁盘随机读取一个数据块的时间大概是20ms,所以这个时间是200ms,这个速度是很慢的。为了提高查询的速度,访问尽量少的数据块,我们采用了“N叉树”让树的高度降下来。这样就减少了访文磁盘的次数及时间。例如一个整数字段的索引,n差不多是1200,对于3层高的树,其能容纳的值为 17亿,也就是说寻找一个数据最多只需要访问3次磁盘。由于N叉树很好的读写性能优势,以及适配磁盘的访问模式,已经被广泛的应用到数据库引擎中了。

磁盘寻址过程:每次访问磁盘的一个块时,磁臂就需移动到正确的磁道上(这段时间为寻址时间),然后盘片就需旋转到正确的扇区上(这叫旋转时延),这套动作需要时间,所以说顺序写比随机写性能高,大部分情况db的最大瓶颈在io;

问题二:B+树的缺点

答:(1) 插入可能会引起数据页的分裂;(2) 删除可能会引起数据页的合并。二者都是比较重的io消耗。所以比较好的方式是顺序插入,这也是我们选择自增主键的原因。

问题三:N叉树的n能调整吗?

 答:树高取决于叶子树(数据行数) 和”N叉树”的N。而N又是页大小和索引大小决定的。

     磁盘读取数据是以磁盘块为基本单位的(1 Block = 4KB),也即是每次最少读4KB,内存页的大小是4KB。为了达到最大性能,B+Tree 的每个节点的大小就是块的大小(4KB),这样每个节点可以一次性全部读到内存,减少磁盘 io 次数。由于节点中只存储 key 和 point。

假设有 n 个 key,那么就有n+1 个point:
32位系统中,int 类型占4个字节,指针占4个字节,则有:4n+4*(n+1)<=4096  n=511。
64位系统中,int 类型占4个字节,指针占8个字节,则有:4n+8*(n+1) <= 4096n = 170;
大概值:32位系统中,B+Tree 的度为512,64位系统中,B+Tree 的度171。
如果 MySQL 的 B+Tree 结构中除了必备的 key 和 point,还有其他结构的话,度会相应减少。

问题4:重建索引需要注意什么?

   二叉树的高度对sql的查询起着一定的影响,另外当数据插入的时候,可能会产生分页,存储空间利用率低,删除的数据也会导致碎片空间,这时候就需要重建优化索引,一般情况很少去优化或者是重建。
   如果是主键索引,无论是删除还是重建主键索引,都会将整个表重建,并且会使所有的二级索引失效,并且会用ROWID来做主键索引。当需要删除和重建普通索引的时候,就只需要删除该普通索引即可,正常来说没有影响。
重建索引的方式:
(1) 离线的业务:整个数据库迁移,先dump出来再重建表;
(2) 使用alter操作:ALTER TABLE TABLE ENGIN=InnoDB;这个命令回原地重建表结构;
(3) 使用repair table,这个取决于存储引擎是否支持;

 

学习笔记,内容简单,用于复习,原内容2月有更新。
##参考资料,《MySql实战详解》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章