Are You OK?主键、聚集索引、辅助索引

每张表都一定存在主键吗?

关于这个问题,各位小伙伴们不妨先自己想一想,再往下寻找答案。

首先公布结论: 对于 InnoDB 存储引擎来说,每张表都一定有个主键(Primary Key)!

让人非常遗憾的是,网络上至今仍然有非常多的文章是这样的描述:”一张表中必须有聚集索引,但不一定需要主键”。前半句是正确的,后半句是大错特错!

Are You OK?主键、聚集索引、辅助索引

对于 InnoDB 存储引擎来说,表采用的存储方式称为 索引组织表(index organizedtable),也即 表都是根据主键的顺序来进行组织存放的。如果主键都没有,表怎么存?

那下面这段没定义主键的建表语句是正确的吗?

CREATE TABLE test(
    a INT NOT NULL,
    b INT NULL,
    c INT NOT NULL,
    d INT NOT NULL,
    UNIQUE KEY(b),
    UNIQUE KEY(d),
    UNIQUE KEY(c)
);

当然是没有任何问题的。

因为 不显示定义主键 != 没有主键

如果在创建表时没有显式地定义主键,InnoDB 存储引擎会按如下方式选择或创建主键:

  • 首先判断表中是否有非空的唯一索引(Unique NOT NULL),如果有,则该列即为主键
  • 如果不符合上述条件,InnoDB 存储引擎自动创建一个 6 字节大小的指针 _rowid 作为主键

如果表中有多个非空唯一索引时怎么办呢? InnoDB 存储引擎将选择建表时第一个定义的非空唯一索引为主键。需要注意的是!主键的选择根据的是非空唯一索引定义的顺序,而不是建表时列的顺序。

比如上面那段代码,有 a、b、c、d 四个列,b、c、d 三列上都有唯一索引。不过 b 列不是非空的,所以不可能成为主键了。而 d 列首先被定义为非空的唯一索引,所以 InnoDB 存储引擎将其视为主键。

B+ 树索引总览

InnoDB 存储引擎支持以下几种常见的索引:

  • B+ 树索引
  • 全文索引
  • 哈希索引

所谓哈希索引也就是得益于哈希算法的快速查找特性,不过哈希索引的致命缺点就是无法范围查询。并且 InnoDB 中哈希索引是自适应的,也就是说 InnoDB 存储引擎会根据表的使用情况自动为表生成哈希索引, 不能人为干预是否在一张表中生成哈希索引

全文索引本文先暂且不做赘述。

再来看 B+ 树索引, B+ 树索引的本质就是 B+ 树在数据库中的实现,它是目前关系型数据库系统中查找最为常用的索引。

关于 B+ 树的数据结构我就不详细说了,B 代表平衡(Balance),而不是二叉(Binary),B+ 树是从最早的平衡二叉树演化而来的,但是 B+ 树不是一个二叉树。

简单介绍下: B+ 树是为磁盘或其他直接存取辅助设备设计的一种平衡查找树。在 B+ 树中,所有记录节点都是按键值的大小顺序存放在同一层的叶子节点上,各叶子节点之间通过双向链表进行连接。

也就是说,B+ 树的叶子节点存储真正的记录,而非叶子节点的存在是为了更快速的找到对应记录所在的叶子节点。如下图是一个高度为 2 的 B+ 树:

Are You OK?主键、聚集索引、辅助索引

另外,需要注意的是, B+ 树索引并不能找到一个给定键值的具体”行”!B+ 树索引能找到的只是被查找数据行所在的”页”。然后数据库通过把页读入到内存,再在内存中进行查找,最后得到要查找的数据

肯定有些小伙伴会懵逼了,”页” 又是什么东西?

这就得说到 InnoDB 存储引擎的逻辑存储结构。

InnoDB 存储引擎中,所有数据都被逻辑地存放在一个空间中,称之为 表空间(tablespace),也就是说我们常说的表,可以看作是 InnoDB 存储引擎逻辑结构的最高层。表空间又由 段(segment)区(extent)页(page) 组成(页有时也称为块 block)。如下图:

Are You OK?主键、聚集索引、辅助索引

页是 InnoDB 磁盘管理的最小单位,在 InnoDB 存储引擎中,默认每个页的大小为 16KB。而页里面存放的东西就是一行一行的记录。

我们接下来要说的 聚集索引(clustered inex)和辅助索引(secondary index)其实都是一种 B+ 树索引。也就是说不管是聚集索引还是辅助索引,其内部都是 B+树,即高度平衡的,叶子节点存放着所有的数据。(需要注意的是,索引是存储引擎负责实现的,因此不是所有的存储引擎都支持聚簇索引)

聚集索引与辅助索引不同之处就是,叶子节点存放的是否是一整行的信息。下文我们会详细解释。

主键和聚集索引的关系

先来看聚集索引,上面我们说过,InnoDB 存储引擎表是索引组织表结构,即表中数据都是按照主键顺序进行存放的。而 聚集索引就是按照每张表的主键构造一棵 B+ 树,同时叶子节点中存放的即为表中一行一行的数据,所以聚集索引的叶子节点也被称为数据节点。

Are You OK?主键、聚集索引、辅助索引

也就是说, 聚集索引能够在 B+ 树索引的叶子节点上直接找到数据。并且由于定义了数据的逻辑顺序,查询优化器能够快速发现到底是哪一段范围的数据页需要扫描。比如用户需要查询一张用户表,查询最后注册的 10 位用户,由于 B+ 树索引的叶子节点是基于双向链表的,所以用户可以快速找到最后一个数据页,并取出 10 条记录。这也就是为什么大部分情况下查询优化器倾向于采用聚集索引了。

可以这么说:在聚集索引中, 索引即数据,数据即索引

另外,由于数据页只能按照一棵 B+ 树进行查找排序,或者说无法同时把数据行存放在两个不同的地方,所以 每张表只能拥有一个聚集索引

讲了这么多,好像还没讲到主键和聚集索引有啥区别。一张表只能有一个主键,并且也只能有一个聚集索引,聚集索引还是按照主键来构建的,那这种种迹象不都表明主键就是聚集索引?

事实上, 主键和索引就不是一个层次的东西!

主键是一种约束,这个约束用来强制表的实体完整性,一个表中只能有一个主键约束,并且主键约束中的列值必须是非空且唯一的。

而聚集索引它作为一种索引,其目的不是为了约束啥,而是为了对数据行进行排序以提高查询的效率,换句话说它决定的是数据库的物理存储结构。

⭐ 形象点说,一个没加聚集索引的表,它的数据是一行一行 无序 地存放在磁盘存储器上的。而如果给表添加了聚集索引,那么表在磁盘上的存储结构就由一行一行排列的结构转变成了 树状结构,也就是 B+ 树结构,换句话说,就是整个表就变成了一个索引,也就是上面提到的 “索引即数据,数据即索引”。

而至于 “主键就是索引” 这种观点的由来,是因为:InnoDB 存储引擎中,每张表都一定存在主键(显示或隐式),而聚集索引依赖于主键的建立,所以如果没有强制指定使用非聚集索引,InnoDB 在创建主键的同时会建立一个唯一的聚集索引(也有些文章称之为 主键索引)。

所以,不要说 “主键就是聚集索引”,应该这样说:” 聚集索引一般都是加在主键上的“。

聚集索引和辅助索引的关系

辅助索引(Secondary Index)也称为 非聚集索引、二级索引。其和聚集索引的最大区别就在于,辅助索引的叶子节点并不包含行记录的全部数据。

简单来说,一行记录我们可以用 “主键 + 其他数据” 这样的组合来标识,聚集索引中的叶子节点存储的就是这一整个组合,而非聚集索引中的叶子节点只存储了这个组合中的主键,那其他数据我怎么获得呢?

非聚集索引的叶子节点说还包含了一个 书签(bookmark),该书签用来告诉 InnoDB 存储引擎哪里可以找到与索引相对应的行数据。

那各位不妨想一想,行数据存储在哪里呢?

没错,上文说过,聚集索引中的叶子节点中存放的就是表中一行一行的数据, 所以 InnoDB 存储引擎的辅助索引中的书签其实就是相应行数据的聚集索引键

也就是说, 辅助索引的叶子节点包含的是:每行数据的主键 + 该行数据对应的聚集索引键

当通过辅助索引来寻找数据时,InnoDB 存储引擎会先遍历辅助索引并通过叶子节点获得某个主键对应的聚集索引键,然后再通过聚集索引来找到一个完整的行记录。

举个例子,如果在一棵高度为 3 的辅助索引树中查找数据,那需要对这棵辅助索引树遍历 3 次找到指定聚集索引键,如果聚集索引树的高度同样为 3,那么还需要对聚集索引树进行 3 次查找,最终找到一个完整的行数据所在的页,因此一共需要 6 次逻辑 IO 访问以得到最终的一个数据页。

另外,很显然的是,辅助索引的存在并不影响数据在聚集索引中的组织,因此 每张表上可以有多个辅助索引

🎉 关注公众号 | 飞天小牛肉,即时获取更新

  • 博主东南大学硕士在读,携程 Java 后台开发暑期实习生,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 技术栈等相关原创技术好文。本公众号的目的就是 让大家可以快速掌握重点知识,有的放矢。关注公众号第一时间获取文章更新,成长的路上我们一起进步
  • 并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.8k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~ 😊
  • 如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 900+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + … 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中。

Original: https://www.cnblogs.com/cswiki/p/15174570.html
Author: 飞天小牛肉
Title: Are You OK?主键、聚集索引、辅助索引

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/575965/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • SQL语言基础

    SQL语言基础 SQL (Structured Query Language:结构化查询语言) 是用于管理关系数据库管理系统(RDBMS)。 SQL 的范围包括数据插入、查询、更新…

    数据库 2023年5月24日
    085
  • 计算字符串中连续出现最多的字符串和长度

    public static void main(String[] args) { // 定义的字符&#x4E3…

    数据库 2023年6月11日
    098
  • 记一次生产事故,Redis内存问题排查与解决

    前几天生产的Redis突然挂掉了,之前都没有太注意过Redis那边的使用情况,这次Redis挂掉重启后,发现在那台服务器上,Redis占用了足足30G的运行内存,这才意识到Redi…

    数据库 2023年6月6日
    092
  • delete-drop语句生成的存储过程

    问题: 有时,您需要在开发过程中操作许多表。 [En] Sometimes you need to manipulate many tables during developmen…

    数据库 2023年5月24日
    0108
  • 无根用户管理podman

    在允许没有root特权的用户运行Podman之前,管理员必须安装或构建Podman并完成以下配置 基础设置 cgroup V2Linux内核功能允许用户限制普通用户容器可以使用的资…

    数据库 2023年6月14日
    086
  • 多线程

    public class 多线程 { static boolean flag = true; static class t1 implements Runnable{ @Overr…

    数据库 2023年6月16日
    0105
  • MySQL 事务和锁

    事务概述 当多个用户访问相同的数据时,在更改数据的过程中,其他用户可能会同时发起更改请求,为了确保数据库记录的更新从一种一致性状态更改为另一种一致性状态,需要使用事务处理,它具有以…

    数据库 2023年5月24日
    067
  • 设计模式之(12)——外观模式

    外观模式(facadePattern)又叫门面模式,隐藏了子系统的复杂实现,为子系统中的一组接口提供了一个统一的访问入口,使得子系统容易被访问或使用,说白了就是把复杂的子系统封装成…

    数据库 2023年6月14日
    085
  • 实现一个简单的Database2(译文)

    前文回顾:实现一个简单的Database1(译文) 译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运…

    数据库 2023年6月11日
    0109
  • MySQL日志

    一、错误日志 错误日志是MySQL中最重要的日志之一,它记录了当mysqld启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时…

    数据库 2023年5月24日
    0107
  • eclipse连接MySQL 8.0.29.0

    推荐文章: eclipse导入JDBC MySQL详细安装 菜鸟java MySQL连接教程 步骤: 找到MySQL的连接Java的jar文件; 如下图: 在eclipse项目文件…

    数据库 2023年5月24日
    0114
  • mysql进阶

    mysql进阶 1.下载二进制格式的mysql软件包 [root@mr ~]# wget https://downloads.mysql.com/archives/get/p/23…

    数据库 2023年5月24日
    0133
  • 员工离职困扰?来看AI如何解决,基于人力资源分析的 ML 模型构建全方案 ⛵

    💡 作者:韩信子@ShowMeAI📘 数据分析实战系列:https://www.showmeai.tech/tutorials/40📘 机器学习实战系列:https://www.s…

    数据库 2023年6月14日
    094
  • 5个必知的高级SQL函数

    5个必知的高级SQL函数 SQL是关系数据库管理的标准语言,用于与数据库通信。它广泛用于存储、检索和操作数据库中存储的数据。SQL不区分大小写。用户可以访问存储在关系数据库管理系统…

    数据库 2023年6月11日
    0104
  • web开发模式

    前后端不分离 返回的是html的内容,需要在服务端拿到数据库的数据,再渲染给模板层,最后将渲染好的模板返回给浏览器! 前后端分离 前后端分离:只需要在浏览器上运行JS代码,使用aj…

    数据库 2023年6月14日
    097
  • Mysql性能调优-工具篇

    首先祭出官方文档(这是5.7的,请自行选择版本): 如果你不想读英语,只需阅读这篇文章: [En] If you don’t want to read English,…

    数据库 2023年5月24日
    085
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球