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)

大家都在看

  • Golang异常处理

    从error的定义说起 type error interface { Error() string } Go 的error类型是一个接口。在Go中,只要实现了接口约定的方法,就等同…

    数据库 2023年6月16日
    076
  • 21粤比武

    先进行密码绕过,在这个界面迅速按下方向键,然后按下e进入编辑模式 找到linux16这一行,将lang编码后面的全部删掉,加上 <span class=”ne-text”&g…

    数据库 2023年6月11日
    089
  • javaWeb知识点大集合!!!

    pom文件: 4.0.0 org.example javaweb_maven 1.0-SNAPSHOT war UTF-8 1.7 1.7 com.github.pagehelpe…

    数据库 2023年6月16日
    077
  • Java学习-第一部分-第二阶段-项目实战:坦克大战【1】

    坦克大战【1】 笔记目录:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 坦克大战游戏 为什么写这个项目✔好玩✔涉及到ja…

    数据库 2023年6月11日
    066
  • Apache ShardingSphere 5.1.2 发布|全新驱动 API + 云原生部署,打造高性能数据网关

    在 Apache ShardingSphere 5.1.1 发布后,ShardingSphere 合并了来自全球的团队或个人的累计 1028 个 PR,为大家带来 5.1.2 新版…

    数据库 2023年6月16日
    092
  • 设计模式之简单工厂

    一、简单工厂:为了客户类和服务类之间的解耦,把对象的创建任务交给第三方类,这个第三方类就充当工厂的作用,严格来说简单工厂不属于23种设计模式之一。 二、实现思路 :创建一个简单工厂…

    数据库 2023年6月14日
    075
  • mysql杂记漫谈

    Hello,大家好,这几天消失了一下,主要是线上系统出了点小bug和sql性能问题,在努力搬砖,就把之前的设计模式系列放了一下下,正好趁这个复习巩固了一下sql执行计划和sql优化…

    数据库 2023年6月14日
    067
  • java基础

    java基础知识图解 软件开发 软件开发 软件,即一系列按照特定顺序组织的计算机数据和指令的集合。有系统软件和应用软件之分。 人机交互方式 图形化界面(Graphical User…

    数据库 2023年6月16日
    058
  • Linux下的ssh、scala、spark配置

    注:笔记旨在记录,配置方式每个人多少有点不同,但大同小异,以下是个人爱好的配置方式. 平台:win10下的ubuntu虚拟机内 所用到的文件:hadoop-2.7.3.tarjdk…

    数据库 2023年6月16日
    0108
  • windows安装mysql8.0.29(ZIP解压安装版本)

    一. 下载mysql 8.0.29软件包 二. 解压,初始化安装 1,打开下载后文件所在目录,使用解压软件解压,打开文件夹!(如图,文件路径不要出现中文!) 2,创建my.ini文…

    数据库 2023年5月24日
    073
  • jdbc-对其中三步的封装

    package com.cqust.utils; import java.sql.*; public class JDBCUtil {static {try {//注册驱动类加载的…

    数据库 2023年6月11日
    072
  • SQL基础语法

    一:构建数据库和表的语法,字段数据类型 [En] One: syntax for building database and table, field data type 1:建库…

    数据库 2023年5月24日
    0104
  • Node版本更新及切换

    Node版本升级 &#x6E05;&#x9664;npm&#x7F13;&#x5B58; npm cache clean -f n&#x6A…

    数据库 2023年6月16日
    0109
  • 慢SQL,压垮团队的最后一根稻草!

    一、什么是慢 SQL 什么是慢SQL? 顾名思义,运行时间较长的 SQL 语句即为慢 SQL! 那问题来了,多久才算慢呢? 这个慢其实是一个相对值,不同的业务场景下,标准要求是不一…

    数据库 2023年6月14日
    092
  • 使用 yum 在 CentOS7 上安装 MySQL8

    时间:2022-07-13安装版本:MySQL-community-8.0.29 0. 删除MariaDB 在CentOS 7中默认有安装MariaDB,这个是MySQL的分支,通…

    数据库 2023年5月24日
    0124
  • 格林童话之祖父和孙子

    从前有个很老很老的老人,眼睛花,耳朵也背,双膝还不住地发抖。每当他坐在餐桌前 吃饭时,汤匙也握不稳,常常把菜汤撒在桌布上,汤还会从嘴边流出来。儿子和媳妇都嫌弃 他,老人只好躲到灶后…

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