B+树的聚簇索引和非聚簇索引保存在哪里?

pyt*_*hon 5 mysql sql indexing b-tree clustered-index

目前我正在阅读B+ Tree基础知识,并对聚集和非聚集索引的空间分配感到困惑。

当我们在 上创建聚集索引时B+ tree,索引将存储在主内存中,并且叶子包含指向实际块的数据指针。块存储在磁盘中,块中包含记录。

  • 通常聚集索引是在主键上创建的
  • 聚集索引只能有一个

现在假设我们有一个表(idname 、 name 、 class ),并且我在和上创建了两个非聚集索引class我的疑问是非聚集索引将存储在哪里?以及如何搜索query类似内容

select id, name, class from table where id = 3, name='Leo' and class='10'
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我的假设:

  • 由于id字段是主键,因此首先使用聚集索引将 id = 3
  • name现在使用和上的非聚集索引class,我们将找到剩余的字段

你认为我的假设正确吗?您能否详细说明一下存储聚集索引的情况?两个索引(聚集索引和非聚集索引是否形成n叉树?)。我无法同时可视化聚集索引和非聚集索引。

Ric*_*mes 3

我正在专门谈论 InnoDB...

(正如PRIMARY KEY你所说)与数据聚集在一起。整个 BTree(数据 + PK)存储在磁盘上的一组块中(而不是“主内存”)。“叶”节点包含所有列。

辅助键是一个单独的 BTree。从结构上来说,这两个 BTree 是相同的,除了叶节点中的内容不同。对于辅助键,其副本PRIMARY KEY被放入叶节点中。因此,当使用二级索引查找一行(“点查询”)时,有两个 BTree 向下钻取 - 一个用于二级索引,另一个用于 PK。

所有块都“缓存”在“buffer_pool”中,因此它们有时位于主内存中,但总是(迟早)保留在磁盘上。(事务日志等)确保“稍后”不会违反数据始终保留的规则。)

你的两张照片是一个很好的开始。然而...

  • 非叶节点链接在一起(如您所示),但它们不一定在磁盘上相邻。当插入新行(或新索引条目)时,块可能会因为已满而“分裂”。这导致块分散在磁盘周围。
  • 叶节点也链接在一起,但可以分散。
  • 对于Unclustered,嗯,建议你重新开始,考虑到PK问题等。

您需要了解比图片试图传达的更高层次的信息:

  • 点查询向下钻取 b 树
  • 二次查找必须进行 2 次向下钻取
  • “范围”扫描(数据或索引)非常有效,因为它们扫描一个块,然后通过底层块之间的双向链接移动到(逻辑上)下一个块。因此,它实际上是一棵 B+Tree,而不仅仅是一棵 BTree。
  • (更多关于射程)WHERE clustered_key BETWEEN ...非常有效
  • (更多关于范围)WHERE secondary_key BETWEEN ...在查找所需的 PK 值方面非常有效,但随后会变成一堆(可能)随机点查询。
  • 所有块对于缓存来说几乎都是等效的。但是(显然?)由于“最近最少使用”算法,非叶节点往往存在于缓存中。(我省略了很多细节。)
  • 聚集索引只能有一个。(除非你愿意复制所有数据。这已经在 InnoDB 之外的几个引擎中完成了。)
  • 一个块包含尽可能多的“记录”(数据或索引或非叶记录)——从 1 到数百条。
  • 默认情况下,一个块为 16KB。(而且不容易改变。)
  • 当 innodb_file_per_table=ON 时,给定表的所有 BTree 都位于单个 .ibd“表空间”中。
  • 当 innodb_file_per_table=OFF 时,所有表的所有 BTree 都位于一个名为 ibdata1 的全局“表空间”中。(再次,过于简单化。)

现在介绍 MyISAM:

  • 一个表的数据位于一个文件 (.MYD) 中。
  • 一个表的所有索引(包括主键)都位于一个文件 (.MYI) 中
  • 所有索引都是 BTree。(数据不是。)
  • 索引的叶节点“指向”数据文件。
  • 索引块为 1KB。
  • 数据文件只是一个随机访问流。

(还有很多细节。)