1. 引言

  索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本500 页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。

2. 索引的常见模型

这里我先给你介绍三种常见、也比较简单的数据结构,它们分别是哈希表、有序数组和搜索树。

哈希表

  哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key 换算成一个确定的位置,然后把 value 放在数组的这个位置。
  不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。
  假设,你现在维护着一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这时对应的哈希索引的示意图如下所示:

  图中,User2 和 User4 根据身份证号算出来的值都是 N,但没关系,后面还跟了一个链表。假设,这时候你要查ID_card_n2 对应的名字是什么,处理步骤就是:首先,将ID_card_n2 通过哈希函数算出 N;然后,按顺序遍历,找到 User2。
  所以,哈希表这种结构适用于只有等值查询的场景,比Memcached 及其他一些NoSQL 引擎。

有序数组

  有序数组在等值查询和范围查询场景中的性能就都非常优秀。还是上面这个根据身份证号查名字的例子,如果我们使用有序数组来实现的话,示意图如下所示:

  这里我们假设身份证号没有重复,这个数组就是按照身份证号递增的顺序保存的。这时候如果你要查 ID_card_n2 对应的名字,用二分法就可以快速得到,这个时间复杂度是O(log(N))。
  所以,有序数组索引只适用于静态存储引擎,比如你要保存的是 2017 年某个城市的所有人口信息,这类不会再修改的数据。

二叉搜索树

  二叉搜索树也是课本里的经典数据结构了。还是上面根据身份证号查名字的例子,如果我们用二叉搜索树来实现的话,示意图如下所示:

  二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。这样如果你要查 ID_card_n2 的话,按照图中的搜索顺序就是按照 UserA -> UserC -> UserF -> User2这个路径得到。这个时间复杂度是 O(log(N))。
  以 InnoDB 的一个整数字段索引为例,这个 N 差不多是1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一个10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。

3. InnoDB的索引模型

  在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+树中的。
  每一个索引在 InnoDB 里面对应一棵 B+ 树。假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引。

mysql> 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),两棵树的示例示意图如下。

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。

  1. 主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
  2. 非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)

基于主键索引和普通索引的查询有什么区别?
3. 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵B+ 树;
4. 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

4. 索引维护

  B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护。以上面这个图为例,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID值为 400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。
  而更糟的情况是,如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。
  除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%。

04 | 深入浅出索引(上)相关推荐

  1. 04 | 深入浅出索引

    索引的常见模型 哈希表:仅使用等值查询 有序数组:二分查找,区间查询友好,更新效率低,仅适用于静态存储引擎 搜索树:由于二叉树高度较高,磁盘IO次数过多,所以实际使用N叉树.树根的数据块缓存于内存,树 ...

  2. 《MySQL实战45讲》——学习笔记04-05 “深入浅出索引、最左前缀原则、索引下推优化“

    04 | 深入浅出索引(上) 1. 什么是索引? 索引的出现其实就是为了提高数据查询的效率,就像书的目录一样,书有500页,每页存的都是书的内容,目录可能只有5页,只存了页码:通过目录能快速找到某个主 ...

  3. mysql建表语句主键自增_MYSQL索引-上

    前言 今天同事做数据清理的时候发现我这边有一张表没有主键,这个表有两个字段,ID和Name,ID作者唯一索引,在我印象里,一个数据表如果没有主键索引,它会内部创建主键索引,创建的标准就是唯一性,我觉得 ...

  4. 在Ubuntu 16.04.6 LTS上升级python 3.5到3.7.3实录

    缘由 我想安装一个python模块you-get,发现只能使用pip3安装,但是我发现我的Ubuntu 16.04.6 LTS上有python3.5,但是没有pip3,也无法成功安装,真是要了我的老命 ...

  5. 在Ubuntu 16.04.6 LTS上安装python3.7和pip3后出现Command '('lsb_release', '-a')' 出错问题的解决方法

    在Ubuntu 16.04.6 LTS上安装python3.7和pip3后出现Command '('lsb_release', '-a')' returned non-zero exit status ...

  6. 在Ubuntu 16.04.6 LTS上升级Go到最新版1.12.5实录

    上一次我在Ubuntu 16.04.3 LTS上从源码安装了Go,当时最新的版本是1.10,参见我之前的博文 https://blog.csdn.net/tao_627/article/details ...

  7. 在Ubuntu 14.04.5 LTS上安装python模块selenium 3实录

    简介 Selenium是python模块库中一组web自动化测试工具集,提供多种语言的API,例如java,python,ruby,.net等,支持Firefox,Chrome,IE,Safari 等 ...

  8. 在Ubuntu 16.04.5 LTS上利用python中的PIL模块压缩一百多兆的单张图片实操

    在前面的博文中,我将300多张电影海报拼接为了一张103MB的巨幅图片,我想拿它做电脑桌面(1080P),但是这么多的图片,存储和加载是个麻烦事儿,需要将它压缩到几MB大小. 在Ubuntu 16.0 ...

  9. 在Ubuntu 16.04.5 LTS上升级python的pip版本实录

    在ubuntu 16.04.5 LTS上使用Python安装模块时,比较顺手的方法是使用pip命令.这次,我在安装一个模块时,老是提示下面的问题,比较不爽.所以,我就照着提示做了一遍,记录下来,以作备 ...

最新文章

  1. java如何定义一个字符栈_Java性能优化之字符串优化处理
  2. 又涨了?2021 年 3 月程序员工资统计新出炉
  3. Linux(Fedora21)安装google chrome浏览器
  4. 通过样式调整input 中password text默认长度
  5. 【Oracle】-【LRU和DBWR】-LRU算法与DBWR中的应用
  6. python爬取汽车之家数据_Python神技能 | 使用爬虫获取汽车之家全车型数据
  7. Java十大常用框架介绍
  8. Word论文排版之样式的使用
  9. 控件ShowWindow(SW_HIDE)不起作用
  10. Rabbitmq 安全账号管理方案
  11. 《计算机网络》——IEEE 802.11 无线局域网、无线局域网的分类、广域网、PPP协议、HDLC协议、链路层设备、冲突域和广播域
  12. xz2显示无法连接服务器,微端网页版无法登入问题解决方法
  13. 唐澳华的亚索有错吗?
  14. C++运算符重载(详解)
  15. es bulk java_es v6.8.3 bulk 异常
  16. python会搞坏电脑吗_Python 操作几个坏习惯,你中了吗?
  17. Spring Boot文件下载断点续传
  18. 基于高密度EEG情绪想象的无监督机器学习
  19. 统计两个日期间工作日的天数
  20. 图像对抗生成网络 GAN学习01:从头搭建最简单的GAN网络,利用神经网络生成手写体数字数据(tensorflow)

热门文章

  1. 使用OpenSSH远程管理Linux服务器
  2. 面向对象三大特性 -- 继承,封装,多态
  3. django - 替换admin的textarea为 富文本
  4. 产品所有者也应该是Scrum教练吗?
  5. WebService开发
  6. matlab信道均衡,使用LMS算法做信道均衡时,更换信道传递函数效果很差
  7. java 处理byte_java - 文件到Java中的byte [] - 堆栈内存溢出
  8. bom event周期_DOM-BOM-EVENT(1)
  9. java是如何写入文件的
  10. 过河问题matlab建模,matlab三对夫妻过河问题