4 深入浅出索引(上)

4 深入浅出索引(上)

这一节分析到底什么是索引,索引是如何工作的

索引的常见模型

索引的出现是为了提高查询效率,但是实现索引的方式有很多,三种常见简单的数据结构:哈希表、有序数组和搜索树

哈希表是一种key-value存储数据的结构,思路很简单,把值放在数组里,用一个哈希函数把key换算成一个确定的值,然后把value放在这个位置。

不可避免多个key值经过hash函数计算,会出现同一个值的情况,处理这种情况就是拉出一个链表。

假设一个身份信息和姓名的表,需要根据身份证查找对应的名字,对应的哈希索引示意图

图中user2user4根据身份证号算出来的值都是n,后面跟了一个链表,如果这时候查询id_card_n2对应的名字是什么,首先将id_card_n2通过哈希函数计算出N,然后顺序遍历,找到user2

注意,图中4id_card_n的值并不是递增的,这样新加的user速度会很快,缺点是做区间查询的速度会很慢(不是有序)。

所以,哈希表这种结构使用于只有等值查询的场景

有序数组在等值查询和范围查询场景中的性能都非常优秀

假设身份证唯一,这个数组按照id_card递增顺序保存,如果需要查id_card_n2对应的名字,用二分法可以快速得到,同时范围查询直接找到值然后向右遍历即可。

但是需要更新数据的时候就麻烦,往中间插入一个记录所有后面的记录都要挪动,成本太高。

所以,有序数组索引只适合静态存储引擎,比如保存2018年某个地区的所有人口信息,这类不会在修改的数据。

二叉搜索树是比较经典的数据结构,每个节点的左叶子节点小于父节点,父节点又大于右叶子节点。

树可以有二叉又可以有多叉,多叉树就是每个节点有多个叶子节点叶子节点之间保存的值从左到右递增,二叉树的搜索效率是最高的,但是实际上大多数的数据库存储却不使用二叉树,原因索引不止存在内存中,还要写到磁盘上。

这里使用N叉树。

innodb的一个整数字段索引为例,这个n差不多1200,树高4的时候,可以存12003次方的值,可以到达17亿,考虑到树根的数据块总是在内存,一个10亿行的表上一个整数字段的索引,查询一个值最多只需要访问3次磁盘。

mysql中,索引是在存储引擎层实现的,不同的engine的索引的工作方式并不一样。

Innodb的索引模型

Innodb中,表都是根据主键顺序以索引的形式存放,称为索引组织表,innodb使用了B+树索引模型,所有数据都存在主键索引B+树索引的叶子节点上

每一个索引都在innodb里面对应一个B+

mysql> create table T(

id int primary key,

k int not null,

name varchar(16),

index (k))engine=InnoDB;

插入值(100,1),(2002),(300,3),(500,5),(600,6),两颗树如下

 

根据叶子节点的内容,分为主键索引和非主键索引

主键索引的叶子节点存的是整行数据,在innodb里,主键索引也叫cluster index,非主键的叶子节点的内容是主键值,secondry index

基于主键索引和普通索引的查询有什么区别

--select * from t where id=500,根据pk查询,只需要搜索id这个索引树

--select * from t where k=5,即普通索引查询,需要先搜索k索引树,得到id值为500,再到id索引树再搜索一次,这个过程称为回表

也就是说,基于二级索引的查询需要多扫描一个索引树,因此,在应用中应该尽量用主键索引去搜索。

索引维护

B+树为了维护索引有序性,在插入新值的时候需要做必要的维护,上面如果插入新值id=700,则只需要在R5记录的后面插入一个新记录。如果插入的id=400

就相对麻烦,需要逻辑上挪动后面的数据,空出位置。如果刚好R5所在的数据页已经满了,根据B+树的算法,需要申请一个新的数据页,然后挪动部分数据过去,称为页分裂,性能会受到影响

除了性能外,页分裂操作还影响数据库的利用率,原本放在一个页的数据,现在分裂到了两个页。

有分裂就有合并,当相邻两个页删除了数据,将会有数据页合并的过程。

自增主键是指自增列上定义的主键not null primary key auto_increment

插入新记录的时候可以不指定id的值,系统会获取当前max(id)+1作为下一条记录的值。

从性能和存储方面,自增主键往往是更合适的选择

 

思考innodbt,如果要重建索引,下面的2sql

--1 普通索引

alter table T drop index k;

alter table T add index(k);

--2 主键索引

alter table T drop primary key;

alter table T add primary key(id);

这两个方法有什么影响,是否合适?

posted @ 2019-06-21 14:20  春困秋乏夏打盹  阅读(351)  评论(0编辑  收藏  举报