Mysql实战45讲学习详情----深入浅出索引(一)

问题:

  什么是索引?

  索引又是如何工作的呢?

索引的作用:

  索引是为了提高数据查询的效率

数据库处理数据的核心概念之一:

  数据库底层存储的核心就是基于这些数据模型的。每碰到一个新数据库,我们需要先关注它的数据模型,这样才能从理论上分析出这个数据库的适用场景。

索引的模型(提高读写数据效率的数据结构):

  哈希表:以键值(key:value)存储的数据结构,用key找value(dict)

    思路:把value放在一个数组里,用哈希函数把key换算成一个坐标,然后把value放在数组的这个坐标上。

    执行步骤:首先将key通过哈希函数算出位置;然后按顺序遍历,找到value。

    优:key值并不是递增的,增加新字典的速度会很快

    劣:因为是无序的,所以哈希引做区间查询很慢。

      例:如果要找在[key1~key5]之间所有的value,那么就需要全部扫描一遍。

    适用场景:哈希表这种结构适用于只有等值查询的场景(Memcached 及其他一些 NoSQL 引擎)

    注:可能不同的key哈希出来的位置是一样的,所以后面会跟一个链表。链表是由单独的字典(user)组成。

    

  有序数组:

    思路:二分法,因为是有序排列所以可以查询中间值,排除一半的key以此类推

    执行步骤:

      key值没有重复:二分法

      区间查询:[key1~key5]先用二分法找到key1(如果不存在则找大于key1的第一个值),然后向右遍历知道找到大于key5的值

    优:查询效率高

    劣:更新数据成本大

      例:如果需要在中间插入一个记录,就必须挪动后面所有的记录

    适用场景:有序数组在等值查询和范围查询场景中的性能就都非常优秀(适用于静态存储引擎)

    

  搜索树(二叉搜索树):

    思路:每个节点的左儿子小于父节点,父节点又小于右儿子(儿子大小是从左往右递增的)

    执行步骤:每个节点都相当于做一次判断,利用判断结果选择正确的路径

    优:搜索效率是最高的,查询和更新的时间复杂度都是O(log(N))

    劣:效率虽然高,但是实际上查询时间特别慢

      因:索引不止存在内存中,还要写到磁盘上

        例:你可以想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间

    适用场景:大多数的数据库存储都不使用二叉树

    注:N叉树模型应用广泛,提高二叉树每个节点的儿子数量(N取决于数据块大小),来减少磁盘的访问平均次数

    

InnoDB 的索引模型:

  表的存储方式:根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。

  使用的索引模型:InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。每一个索引在 InnoDB 里面对应一棵 B+ 树。

例子:  

假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引。

  create table T(id int primary key, k int not null, name varchar(16),index (k))engine=InnoDB;

表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下

  

图中索引类型分为:

  主键索引:主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。

  非主键索引:非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。

  两者区别:

    ①如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;

    ②如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

    总结:

      非主键索引的查询需要多扫描一棵索引树,因此在查询中尽量使用主键索引。

索引维护:

  为了保持索引的有序性,插入数据时必须做必要的维护。

    顺序增加:只需要在最大行后面插入新纪录即可

    中间插入:需要逻辑上挪动后面数据,空出位置

    当前数据页满:页分裂,申请一个新的数据页,把部分数据挪动过去。PS:此操作会影响性能和数据页利用率

    页合并:页分裂的逆过程

  自增主键是指自增列上定义的主键,在建表语句中一般是这么定义的: NOT NULL PRIMARY KEY AUTO_INCREMENT。

  自增主键场景:一般情况下建议创建一个自增主键,这样非主键索引占用的空间最小

  非自增主键场景:有业务逻辑的字段,值过长的字段类型

    例外:部分有业务逻辑的字段也可以作为主键(KV场景)

      1.只有一个索引

      2.该索引必须是唯一索引

      由于没有其他索引,所以也就不用考虑其他索引的叶子节点大小的问题。

    PS:主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小

猜你喜欢

转载自www.cnblogs.com/lvzhenhua/p/12668377.html