跳到主要内容

磁盘结构和存储介绍

本章内容

数据库服务器通过管理自己的 I/O 获得高性能。数据库服务器管理存储、搜索和检索。当数据库服务器存储数据时,它创建在以后搜索和检索数据时需要的结构。数据库服务器磁盘结构还存储和跟踪管理日志记录和备份所需的控制信息。数据库服务器包含确保数据一致性(物理和逻辑)所需的所有信息。

在阅读本章之前,请先熟悉 GBase 8s 管理员指南 中的 数据存储在哪里 一章中磁盘空间术语和定义。

本章讨论与磁盘数据结构相关的以下主题:

  • 数据库空间的结构和存储
  • 简单大对象的存储
  • Sbspace 结构
  • 时间戳记
  • 数据库和表的创建:磁盘上发生什么

数据库空间结构和存储

本节研究数据库服务器用于在数据库空间中存储数据的磁盘结构和存储技术。

root dbspace 结构

作为磁盘空间初始化的一部分,数据库服务器初始化 root dbspace 初始 chunk 中的特定结构。

这些结构是:

  • 12 个保留页
  • 第一个 chunk 可用列表页
  • tblspace tblspace
  • 物理日志
  • 逻辑日志文件
  • 数据库 tblspace

ROOTNAME 、ROOTOFFSET 、ROOTPATH 和 ROOTSIZE 配置参数指定 root dbspace 初始 chunk 的大小和位置。如果 root dbspace 已镜像,那么 MIRROROFFSET 和 MIRRORPATH 配置参数指定镜像块的位置。

可使用 oncheck -pe 命令来查看 root chunk 的结构。有关更多信息,请参阅 oncheck -ce 、-pe: 检查可用 chunk 列表。

保留页

Root Dbspace 的初始 chunk 的前 12 页是保留页。每个保留页包含数据库服务器所使用的特定控制和跟踪信息。

要获取保留页内容的列表,请执行 oncheck -pr 命令。要同时列出有关物理日志和逻辑日志页(包括物理日 志页)的信息,请执行 oncheck -pR 命令。

以下示例显示了时间间隔检查点的 oncheck -pr 输出:

Time of checkpoint      10/25/2005 17:05:20
Checkpoint Interval 1234

数据库服务器也存储了当前配置参数的信息,这些信息存储在一个名为 PAGE_CONFIG 的保留页中。如果你用命令行更改参数配置信息,并在没有关闭和重启数据库服务器的情况下运行 oncheck -pr 命令,该命令输出的配置值将与保留页中当前的值不匹配。oncheck 程序用例会返回一个警告消息。

以下示例显示了 PAGE_CONFIG 保留页的输出。

...
Validating GBase 8s database server reserved pages - PAGE_CONFIG
ROOTNAME rootdbs
ROOTPATH /home/dyn_srv/root_chunk
ROOTOFFSET 4
ROOTSIZE 8000
MIRROR 0
MIRRORPATH
MIRROROFFSET 0
PHYSFILE 1000
LOGFILES 5
LOGSIZE 500
MSGPATH /home/dyn_srv/online.log
CONSOLE /dev/ttyp5
... ...

常规 Dbspace 的结构

磁盘空间初始化后,可添加新的 dbspace 。创建 dbspace 时,至少向 dbspace 指定一个 chunk(原始或格式化的磁盘空间)。该 chunk 称为 dbspace 的初始 chunk 。 图 1 说明了常规(非根)dbspace 初始 chunk 的结构。

首次创建 dbspace 时,它包含以下结构:

  • 两个保留页
  • chunk 中第一个 chunk 可用列表页
  • 此 dbspace 的 tblspace tblspace
  • 未使用页

图:常规 dbspace 的初始 chunk

附加 Dbspace Chunk 的结构

可以创建包含多于一个 chunk 的 dbspace 。Dbspace 中的初始 chunk 包含了数据库空间的表空间 tblspace 。附加 chunk 则不包含。当附加 chunk 第一次创建时,包含以下结构:

  • 两个保留页
  • 第一个 chunk 可用列表页
  • 未使用页

下图说明了 Dbspace 中所有附加 chunk 的结构。(该结构也适用于 root dbspace 的附加 chunk 。)

图: 附加 Dbspace Chunk

镜像 chunk 的结构

每个镜像 chunk 的大小必须与其主 chunk 相同。创建镜像 chunk 时,数据库服务器立即将主 chunk 的内容写入镜像 chunk 中。

镜像 chunk 包含于主 chunk 相同的控制结构。在数据库服务器将 blobspace 、sbspace 或 dbspace chunk 的镜像在线后,它们包含与其主对象相同的物理内容。

下图说明了 chunk 创建之后所显示的镜像 chunk 结构。

图: 镜像 chunk 结构

由于镜像 chunk 的所有空间都保留用于镜像,所以镜像 chunk 结构总是显示没有可用空间。

chunk 可用列表页的结构

在每个 chunk 中,最后一个保留页后的页是跟踪 chunk 中可用空间的一个或多个 chunk 可用列表页的第一页。对于 non-root chunk ,可用空间的初始长度等于该 chunk 的大小减去 3 页。如果容纳新条目需要额外的 chunk 可用列表页,那么在 chunk 中的一个可用页中创建一个新的 chunk 可用列表页。图 1 说明了可用列表页的位置。

使用 oncheck -pe 获得 chunk 中页的物理布局。 有关更多信息,请参阅 oncheck -ce 、-pe: 检查可用 chunk 列表.

图:可用列表页

tblspace tblspace 的结构

每个 dbspace 包含一个名为 tblspace tblspace 的表空间,它描述 dbspace 中的所有的 tblspace 。当数据库服务器创建 tblspace 时,它在表空间 tblspace 中放入一个条目,该条目描述新创建 tblspace 的特征。您不能删除或移动表空间 tblspace 的 chunk 。

dbspace 最多可以有 2**20 个 tblspace 。

第一个 Extent 和下一个 Extent 的缺省大小取决于 dbspace 是否为 root dbspace ,如下表所示。

每个 extent 的缺省大小和 dbspace 类型

dbspace 类型第一个 Extent 的缺省大小下一个 Extent 的缺省大小
root● 500 KB ( 2 KB 页的系统)
● 1000 KB ( 4 KB 页的系统)
● 100 KB ( 2 KB 页的系统)
● 200 KB ( 4 KB 页的系统)
non-root● 100 KB ( 2 KB 页的系统)
● 200 KB ( 4 KB 页的系统)
● 100 KB ( 2 KB 页的系统)
● 200 KB ( 4 KB 页的系统)

您可以通过以下方式为表空间 tblspace 的第一个 Extent 和下一个 Extent 指定非缺省的大小:

  • 对于 root dbspace ,设置 TBLTBLFIRST 和 TBLTBLNEXT 配置参数。
  • 对于 non-root dbspace ,在创建 dbspace 时请使用 onspaces 命令 -ef 和 -en 选项。

tblspace tblspace 条目

Tblspace tblspace 描述有关 tblspace 的特征。

要显示有关 tblspace 的信息,请使用 oncheck -pt 命令。

组件描述
页头24 字节,标准页头信息
页结束时间戳记4 字节
Tblspace 头136 字节,常规 tblspace 信息
Tblspace 名称database.owner.tablename 或 database.owner.indexname
典型 30-40 字节长但是可以更长,取决于该名称的长度
列信息8 字节 每一特定的列
特定列是指定义为 VARCHAR 、BYTE 、TEXT 或用户自定义数据类型
索引信息对于连接的索引,该分区上的每个索引都包含 20 字节的头,头包含关于索引的一般信息。后跟索引每列组成部分的 4 字节条目
对于拆离索引,在该索引上每列包含 4 字节条目
Extent 信息分配给该 tblspace 每个 extent : 10 字节条目 + 10 字节信息
在 tblspace 碎片整理的过程中,会使用更多的字节

tblspace 编号

tblspace tblspace 中描述的每个 tblspace 都接收到一个 tblspace 编号。该 tblspace 编号的值与 systables 系统目录表中的 partnum 字段和 sysfragments 系统目录表中 partn 字段所存储的值相同。

以下 SQL 查询检索数据数据库中每个表的 partnum(它们可位于几个不同的 dbspace 中) 并将它显示为表名和 partnum 的十六进制表示法:

SELECT tabname, tabid, partnum, HEX(partnum) hex_tblspace_name FROM systables

如果输出包括具有表名的行但 partnum 为 0,那么该表由两个或两个以上表分片组成,每分片为与其自己的 dvspace 中。例如:图1 显示了名为 account 但 partnum 为 0 的表。

图1:带有 partnum 值的 systables 查询的输出

cankao34.png

要获取组成表的各个分片的实际 tblspace 编号,必须查询同一数据库的 sysfragments 表。 图2 显示了 图1 中的 account 表有三个表分片和三个索引分片。

图2: 带有 partn 值的 sysfragments 表的输出

cankao35.png

tblspace 编号元素

tblspace 中的第一页是逻辑页 0 。(物理页编号引用 chunk 中页的地址。)Root 空间表空间 tblspace 总是包含在第一个 dbspace 以及表空间 tblspace 的逻辑页 1 中。(位图页是页 0 。)

tblspace tblspace 大小

当初始化 dbspace 时,这些 tblspace tblspace 页作为 extent 进行分配。如果数据库服务器尝试创建表,但是 tblspace tblspace 已满,那么数据库服务器将向该 tblspace 分配下一个 extent 。

当从 dbspace 除去表时,也会删除该表在t blspace tblspace 的相应条目。

tblspace tblspace 位图页

tblspace tblspace 的第一页与任何初始 extent 的第一页一样,是描述接下来那些页的页充满度的位图。接下来的每一页在位图页上都有一个条目。如果需要,附加位图页位于分配给 tblspace 的整个邻接空间中,排列使得每个位图只描述紧跟它的页,知道下一位图或 dbspace 的结束。在 tblspace 页中,位图页以显著的间隔减少。每个位图页描述紧跟它的固定数量的页。

database tblspace 的结构

database tblspace 仅出现在 root dbspace 的初始 chunk 中。对于数据库服务器管理的每个数据库,database tblspace 都包含一个条目。下图说明了 database tblspace 的位置。

图: root dbspace 初始 chunk 中 database tblspace 的位置

database tblspace 编号

database tblspace 的 tblspace 编号始终是 0x100002。如果 database tblspace 是活动的,那么该 tblspace 编号出现在 onstat -t 列表中。

database tblspace 条目

每个database tblspace 条目包括以下 5 个组成部分:

  • 数据库名
  • 数据所有者
  • 数据库创建的日期和时间
  • 该数据库的 systables 系统目录表的 tblspace 编号
  • 标识日志记录方式的标示

database tblspace 包含在数据库名上的唯一索引,以确保每个数据库是唯一命名的。对于任何数据库,systables 表描述数据库中每个永久表。因此,database tblspace 只指向位于任何其他地方的详细数据库信息。

当初始化 root dbspace 时,分配 database tblspace 的第一个 extent 。database tblspace 的初始 extent 大小和下一个 extent 大小为 4 页。 您不能修改这些值。

Extent 的结构和分配

本节涉及以下主题:

  • Extent 结构
  • Next-extent 分配

Extent 结构

Extent 是 dbspace 中邻近页的集合。每个永久数据库表都有两个 extent 大小与其相关联。初始 extent 大小是首次创建表时分配给表的千字节数。Next-extent 大小是当初始 extent 以及随后的每个 extent 变满时分配给表的千字节数。

blobspace 不使用 extent 。

Extent 大小

第一个和下一个 extent 的缺省值是 16 千字节。如果在一个特别的 dbspace 中,它的转换比 4 页小,数据库服务器会使用最小的 extent 大小 — 4 页。 如果 dbspace 的空间为 8 千字节,而它要转换成 2 页,该数据服务器将增加 extent 大小到 32 千字节。

Extent 的最大大小是 2**31 页,等价于最大 chunk 大小。

如果 chunk 小于最大大小,那么最大 chunk 大小取决于 chunk 中可用的相邻空间。

保存索引分片的 tblspace 对 extent 大小遵循不同的规则。数据库服务器根据相应的表分片的 extent 大小来确定这些 dbspace 的 extent 大小。数据库服务器使用行大小与索引键大小的比率为索引 tblspace 指定适当的 extent 大小。分区中 extent 的最大数量是 32767 。

表 Extent 中的页类型

在 extent 中,个别页包含不同类型的数据。表的 Extent 页可以分成以下类别:

  • 数据页

数据页包含表的数据行。

  • 位图页

位图页包含 extent 中每页充满度的控制信息。

  • blobpage

blobpage 包含与数据行一起存储在 dbspace 中的 TEXT 和 BYTE 数据。驻留在 blobspace 中的 TEXT 和 BYTE 数据存储在 blobpage (一种与 dbspace blobpage 结构完全不同的结构)中。

  • 可用页

可用页是 extent 中为 tblspace 使用所分配的,但其功能还未经过定义的页。可用页可用于存储任何类型的信息:数据(包括 TEXT 或 BYTE 数据类型) 、索引或位图。

下图说明了非分片表的可能结构,它具有 8 页的初始化 extent 大小和 16 页的 next-extent 大小。

图: 表的 Extent 结构

索引 Extent 中的页类型

数据库服务器将索引页存储到不同于与其相关联的表的 tblspace 中。在 extent 中,个别索引页包含不同类型的数据。索引页可以分为以下类别:

  • 索引页(根、分支和叶页)

索引页包含表的索引信息

  • 位图页

位图页包含监视 extent 中每页充满度的控制信息

  • 可用页

可用页是 extent 中为 tblspace 使用所分配的,但其功能还未经过定义的页。可用页可用于存储任何类型的信息:数据、索引、 TEXT 或 BYTE 数据或位图。

除非显式指定了连接的索引,否则所有索引都是拆离的。

重要

分配用于表分片的 Extent 不包含索引页。分片表的索引页总是驻留在单独的 tblspace 中。

下图说明了索引的 extent 结构。

图: 索引的 Extent 结构

Next-Extent 分配

在初始化 extent 填满后,数据库服务器尝试分配相邻磁盘空间的另一个 extent 。数据库服务器所遵循的过程称为 next-extent 分配。

Tblspace 的 extent 作为表的 tblspace tblspace 信息的一个组成部分进行跟踪、分配用于任何 tblspace 的 extent 的最大数目依赖于应用程序和机器,因为它随 tblspace tblspace 条目上的可用空间量变化 。

Next-Extent 大小

数据库服务器分配用于下一个 extent 的千字节数一般等于 SQL 语句 CREATE TABLE 中所指定的下一个 extent 的大小。然而,next-extent 分配的实际大小肯会偏离指定大小,因为分配过程考虑以下三个因素:

  • 该 tblspace 现有 extent 的数量
  • Chunk 和 Dbspace 中的相邻空间的可用性
  • 现有 tblspace extent 的位置

在以下段落和 图: Next-Extent 分配策略 中解释了这些因素中的每一个对 next-extent 分配的影响。

Extent 大小加倍

对于永久表或用户自定义临时表,所分配的下一个 extent 的大小都将自动加倍。将加倍到 128 千字节 (KB) 。例如:如果创建 NEXT SIZE 等于 15 KB 的表,那么数据库服务器将第一个 extent 的大小分配成 15 KB 。下一个 extent 的大小分配成 30 KB,下下个 extent 的大小分配成 60 KB。当 extent 的大小达到 128 KB ,当且仅当表中剩余空间少于表的总分配空间的 10% 时,extent 的大小才会加倍。

对于系统创建的临时表,next-extent 大小在添加了 4 个 extent 后开始加倍。

相邻空间的缺少

如果数据库服务器无法在第一个 chunk 中找到下一个 extent 指定大小的可用相邻空间,那么将搜索延伸到 dbspace 中的下一个 chunk 中。Extent 是不允许跨 chunk 的。

如果数据库服务器无法在 dbspace 的任何地方找到足够的相邻空间,那么它向该表分配最大可用数量的相邻空间。(最小的分配为 4 页。缺省值为 8 页)如果分配是可能的,那么即使所分配的空间量小于所请求的量,也不会返回任何错误消息。

同一表的 Extents 合并

如果分配用于下一个 extent 的磁盘空间是与已分配给相同表的磁盘空间物理相邻的,那么数据库服务器分配该磁盘空间但不将新分配视作单独 extent 。相反,数据库服务器扩展现有相邻 extent 的大小。此后,所有磁盘空间报告将该分配作为现有 extent 的扩展进行反映。即,所报告 extent 的数量始终是物理上不同 extent 的数量,而不是已分配的下一个 extent 的次数加 1 (初始 extent)。下图说明了 extent 分配策略。

图: Next-Extent 分配策略

在磁盘空间作为 extent 的一部分分配给 tblspace 后,该空间保持专用于该 tblspace ,即使其中包含的数据已删除也是如此。

dbspace 页的结构和存储

数据库服务器 I/O 的基本单位是页。页大小可由计算机而异。

在 GBase 8s 中,页大小依赖于操作系统。

非分片表中的行

数据库服务器可以存储长于一页的行。数据库服务器还支持 VARCHAR 数据类型,这导致可变长度的行。因此,行并不遵循单一格式。

如果表包含类型为 VARCHAR 的一列或多列,那么表中行的长度不一定相同。另外,在最终用户修改 VARCHAR 列中包含的数据时,此类表的行长度可能会变化。

行长度可能会大于一页。

TEXT 和 BYTE 数据并不存储在数据行中。相反,数据行包含指向数据位置的 56 字节的描述符。该描述符可以指向 dbspace 页。

描述符可以指向 blobspace blobpage。

rowid 的定义

GBase 8s 使用两种不同类型的 rowid 来标识表中的数据:

  • 顺序 rowid

这些 rowid 是表中的字段且指定给使用 WITH ROWID 选项所创建的表。

  • 内部 rowid

数据库服务器用唯一的内部 rowid 标识表中的每个数据行。该 rowid 用于标识行在数据库空间中的位置。

要获得表的内部 rowid ,请使用 oncheck -pD 选项。要了解更多信息,请参阅 oncheck -cd 和 oncheck -cD :检查页 。

在分片表中,术语 rowid 是制定义在表中的物理位置的唯一 4 字节整数。包含数据行第一字节的页是由 rowid 所指定的页。该页称为数据行主页。

分片表也可能有 rowid ,但它们是以另一种方式实现的。

rowid 的使用

非分片表中的每一行数据行都由一个不变的 rowid 唯一标识。创建非分片表的索引时,rowid 存储在该数据行所属的表相关联的索引页中。当数据库服务器需要数据行时,它搜索该索引来查找键值并使用相应的 rowid 来定位所请求的行。如果该表未经索引,那么数据库服务器可能会顺序读取表中的所有行。

最后,行可能超出其原始存储位置。如果发生这种情况,那么指向数据行新位置的转发指针将留在 rowid 所定义的位置。转发指针本身就是 rowid ,它定义数据行现在存储页上的页和位置。

分片表中的行

与非分片表中的行不一样,数据库服务器不 向分片表中的行指定 rowid 。如果想要按 rowid 访问数据,那么必须显式创建 rowid 列,如 GBase 8s 性能指南 中描述的那样。如果用户应用程序试图引用未包含显式创建的 rowid 的分片表中的 rowid ,那么数据库服务器向应用程序返回相应的错误代码。

以 rowid 访问分片表中的数据

从应用程序角度来看,分片表中 rowid 列与非分片表中 rowid 的功能是一样的。然而,与非分片表中 rowid 不一样,数据库服务器使用索引将 rowid 标识映射到物理位置上。

当数据库服务器使用 rowid 列访问分片表中的行时,它在尝试访问该行前使用该索引查找该行的物理地址。对于非分片表,数据库服务器使用没有索引查找的直接物理访问。结果,使用 rowid 访问分片表中的行所花时间比使用 rowid 访问非分片表中的行所花时间稍长。由于维护分片表的 rowid 索引的成本,您还应期望插入和删除处理的性能影响较小。

主键访问可能导致许多情况下(特别是并行访问时)性能的显著提高。

关于使用 rowid 的建议

建议应用程序开发者使用主键而不是 rowid 作为存取方法。因为主键是在 SQL 的 ANSI 规范中定义的,所以使用它们访问数据使应用程序的可移植性更好。

数据行格式和存储

数据行的可变长度对于行存储产生以下结果:

  • 一页可能包含一个或多个整行。
  • 一页可能包含一个或多行的一部分。
  • 一页可能包含整行和行的一部分的组合。
  • 行的大小可能会在更新后增大,并变得太长而无法返回到行中原来的存储位置。

以下段落描述了在数据存储过程中数据库服务器所遵循的准则。

行的存储

为使检索时间最小,除非必要,否则不要跨页边界断行。短于一页的行总是作为整行进行存储的。当可用字节计数少于存储最大大小的行所需的字节数时,也被视为已满。

行的位置

当数据库服务器接收长于一页的行时,该行存储在与所需要的同样多的整页中。然后,数据库服务器以小于一个满页的长度存储拖尾部分。

包含行的第一个字节的页是行主页。主页的编号成为 rowid 所包含的逻辑页号。主页后的每个满页称为大剩余页。如果行的拖尾部分小于一个满页,那么它存储在剩余页上。

在数据库服务器创建剩余页以容纳长行之后,它可以使用该页中剩余空间存储其他行。

下图说明了主页、大剩余页和剩余页的概念。

图: 剩余页

页压缩

随着时间的流逝,页上的可用空间可能变成分段的。当数据库服务器试图存储数据时,它首先对照页上的可用字节数检查行长度,以确定该行是否适合。如果可以获得足够的空间,那么数据库服务器检查该页是否包含足够的相邻可用空间以容纳该行(或行的部分)。如果可用空间是不相邻的,那么数据库服务器调用页压缩。

分片表的结构

尽管表分片对应用程序是透明的,但作为数据库服务器管理员,您应知道数据库服务器是如何将磁盘空间分配于表分片以及数据库服务器是如何标识那些分片中的行的。

每个表分片都有自己的具有唯一 tblspace_id 或 fragment_id 的 tblspace 。图 1 显示了驻留在相同 dbspace 的不同分区上的分片表的磁盘分配。

图: 分片表的磁盘结构

连接索引

如果使用连接索引,索引和数据的分片方式是一样的。您可以决定是将索引页与相应的数据页存储在同一个 dbspace 中,还是将它们存储在不同的 dbspace 中。

拆离索引

对于拆离索引,表分片和索引分片都存储在不同 dbspace 的 tblspace 中。

B-Tree 索引页的结构

本节提供有关 B-tree 索引页结构的一般信息。它是为对此结构感兴趣的读者编写的概述。

B-tree 术语的定义

数据库服务器使用 B-tree 结构组织索引信息。

下图显示了一个完全形态的 B-tree 索引是由以下三种不同类型的索引页或节点组成的:

  • 一个根节点

根节点包含指向分支节点的节点指针。

  • 两个或多个分支节点

分支节点包含指向叶节点或其他分支节点的指针。

  • 多个叶节点

叶节点包含索引项和指向其他叶节点的水平指针。

每种节点都发挥不同的功能。以下各节描述了每种节点及其在索引建立中所扮演的角色。

图: 完整的 B-Tree 结构

索引项

索引的基本单位是索引项 。索引项包含代表特定行的索引列值得键值。索引项还包含数据库服务器用于定位数据页中的行的 rowid 信息。

索引节点

节点是存储一组索引项的索引页。

作为代替传统 B-Tree 索引的树索引

不像传统的 B-tree 索引,一个树节点是一个更大的 B-tree 节点,它可以被划分成更小的子树与多个根节点和较少的层次。当您想减少根节点的连接并允许更多并发用户访问索引而无需等待时,您可以创建树节点来代替 B-tree 节点。

索引的逻辑存储

本节介绍数据库服务器如何创建并填充索引的概述。

根节点和叶节点的创建

当创建空表的索引时,数据库服务器分配一个索引页。该页代表根节点并保留为空,直到在该表中插入数据。

起初,根节点以与叶节点相同的方式发挥功能。对于插入表中的每一行,数据库服务器在根节点中创建并插入索引项。下图说明了根节点在其填充之前是什么样的。

图: 根节点

当根节点的索引项被填满时,数据库服务器通过以下步骤分割根节点:

  • 创建两个叶节点
  • 将大约一半的根节点条目移动至每个新创建的叶节点中
  • 在根节点中放置叶节点的指针

当您将新行添加到表中时,数据库服务器将索引项添加到叶节点中。当叶节点填满时,数据库服务器创建新的叶节点,将已满索引节点的一部分内容移动到新节点中,并在根节点中添加指向新节点的节点指针,

例如:假如 下图中的叶节点 3 已满。当发生这种情况时,数据库服务器添加另一个叶节点。数据库服务器从叶节点 3 将一部分记录移动至新的叶节点中,如下图所示。

图: 在叶节点 3 填满后创建叶节点 4

分支节点的创建

最终,当向表添加行时,数据库服务器用指向所有现有叶节点的节点指针填充根节点。当数据库服务器分割另一个叶节点,而根节点没有空间用于额外的节点指针时,那么发生以下过程。

数据库服务器分割根节点并将其内容分到两个新创建的分支节点上。随着索引项的添加,越来越多的叶节点被分割,这导致数据服务器添加更多的分支节点。最终,根节点充满了指向这些分支节点的指针。当发生这种情况时,数据库服务器重新分割根节点。然后,数据库服务器在根节点和较低的分支级别之间创建另一个分支级别。该过程导致 4 个级别的树,它带有一个根节点、两个分支级别和一个叶级别。B-tree 结构可以这种方式继续增长到最大 20 级。

分支节点可以指向其下面的其他分支节点(对于四级或更多的大索引来说)或指向叶节点。在下图中,分支节点只指向叶节点。左分支节点中的第一项包含与最左的叶节点中的最大项相同的键值以及指向它的指针。第二项包含下一叶节点中的最大项和一个指向它的节点指针。分支节点中的第三项只包含指向下一个更高叶节点的指针。根据索引的增长,在索引生命周期中的以后某个时点,除了指针之外,此第三项可能还包含实际键值。

图: 分支节点的典型内容

重复的键值

当多行的索引项列的值完全相同时,发生重复键值。例如:假设 B-tree 结构的第三个和第四个叶节点包含键值 Smith 。进一步假设该值重复 6 次,如下图说明的那样。

图: 叶节点 3 和 4

第三个叶节点上的第一项包含重复的键值 Smith 以及包含重复键值的表中第一个物理行的 rowid 信息。为节省空间,第二项不重复键值 Smith 但只包含 rowid 信息。在整个页上继续该过程;页上不存在其他键值,只有 rowid 信息。

第四个叶页上的第一项也包含重复键值和 rowid 信息。后续项只包含 rowid 信息。

现在考虑分支节点。分支节点中的第三项包含与第三叶节点中的最大项相同的键值和 rowid ,并且有一个指向它的节点指针。第四项将只包含指向第四叶节点的节点指针,这样就节省了附加重复键值的空间。

键值锁定

为了增加并发性,数据库服务器支持 B-tree 索引中的 键值 锁定。键值锁定只锁定键的值而非 B-tree 索引中的物理位置。

键值锁定的一个最重要的用途是确保唯一键在直到删除它的事务结束时一直保持唯一。如果没有这种保护机制,用户 A 可能删除事务中的唯一键,用户 B 可能在事务提交之前插入具有相同键的行。此应用场合使得用户 A 不肯执行回滚。简直锁定阻止用户 B 插入行,直到用户 A 的事务结束。

相邻键的锁定

如果具有可重复读取的隔离级别,那么要求数据库服务器保护读取集。读取集由符合查询的 WHERE 子句中过滤条件的行组成。为保证这些行不改变,数据库服务器获得与读取集的最右端项相邻的索引项上的索。

释放的索引页

当数据库服务器从节点中物理除去索引项并释放索引页,那么释放的页是可再用的。

填充索引

创建索引时,可以指定希望的填充索引的密度。索引填充因子是索引构建过程中填充的每个索引页的百分率。使用 CREATE INDEX 语句的 FILLFACTOR 选项或 FILLFACTOR 配置参数设置填充因子。此选项对于预期在构建后不会增长的索引特别有用。

计算索引的长度

对于非 VARCHAR 数据类型,索引项的长度的计算方法是:键值的长度加上 5 字节,这 5 字节用于描述与键值相关联的每个 rowid 信息。

索引中的键值长度通常是固定的。如果索引保存 VARCHAR 数据类型的一列或多列的值,那么键值的长度至少是键中每个 VARCHAR 值长度加一的总和。

在 GBase 8s 中,键值的最大长度是 390 字节。构成键的 VARCHAR 列的组合大小必须小于 390 减去每个 VARCHAR 列的额外字节。例如:数据库服务器构建用于以下语句的索引键长度等于 390 或 ((255+1) + (133+1)):

CREATE TABLE T1 (c1 varchar(255, 10), c2 varchar(133, 10));
CREATE INDEX I1 on T1(c1, c2);

函数索引

函数索引是一种其所有键都派生于函数结果的索引。例如:如果有一个图片列和一个标识主色的函数,那么可以对函数结果创建索引。这种索引将是您能快速检索具有相同主色的所有图片,而不用重新执行该函数。

函数型索引与任何其他 B-tree 树索引一样也使用 B-tree 结构。唯一的区别是只要是函数参数的那一列更改,就在插入或更新过程中应用确定函数。

要创建函数索引,请使用 CREATE FUNCTION 和 CREATE INDEX 语句。

R-Tree 索引页的结构

依赖于一维键值排序的索引结构对空间数据不起作用;例如:二维几何形状 (例如:圆、正方形和三角形)。对空间数据 (例如地理信息系统 ( GIS )和计算机辅助设计(CAD)应用程序中使用的数据)的有效检索需要处理多维数据的存取方法。数据库服务器实现 R-tree 索引来有效存取空间数据。

简单大对象的存储

本节解释数据库服务器用于存取简单大对象 (TEXT 或 BYTE 数据)的结构和存储技术。

blobspace 的结构

当创建 blobspace 时,可以指定数据页的有效大小,这称为 blobpage 。Blobspace 的 blobpage 大小是在创建 blobspace 时指定的。Blobpage 大小必须是页大小的倍数。Blobspace 中的所有 blobpage 的大小都是相同的,但 blobpage 的大小在 blobspace 之间可能变化。Blobpage 大小可能大于页大小,因为存储在 blobspace 中的数据从不写入共享内存中的大小为页的缓冲区中。

定制 blobpage 大小的好处是存储效率。在 blobspace 中,TEXT 和 BYTE 数据存储在一个或多个 blobpage 中,简单大对象不共享 blobpage 。当 TEXT 或 BYTE 数据等于或稍小于 blobpage 大小时,存储是最有效的。

Blobspace 自由图页和位图页是作为数据库服务器页指定的大小。这使它们能够读入共享内存和被记录下来。

当首次创建 blobspace 时,它包含以下结构:

  • Blobspace 自由图页
  • 用于跟踪自由图页的 blobspace 位图
  • 未使用的 blobpage

dbspace blobpage 的结构

存储在 dbspace 中的 TEXT 或 BYTE 数据是存储在 blobpage 中的。Dbspace blobpage 的结构类似于 dbspace 数据页的结构。唯一的区别是可以与 TEXT 或 BYTE 数据一起存储在数据区域的额外 12 字节。

如果多个简单大对象可以适合一个页或如果简单大对象的多个拖尾部分可以适合页,那么简单大对象可以共享 dbspace blobpages 。

存储在 dbspace 页中的每段 TEXT 或 BYTE 数据前面可能有多达 12 字节的信息,这些信息不出现在任何其他 dbspace 页上。这些额外字节是开销的。

简单大对象存储和描述符

包含 TEXT 或 BYTE 数据的数据行在行本身中不包含数据。数据行包含 56 字节的描述符和一个指向数据第一个分段存储位置的转发指针(rowid)。

描述符可指向以下项之一:

  • 页(如果数据存储在 dbspace 中)
  • blobpage (如果数据存储在 blobspace 中)

简单大对象的创建

当插入含 TEXT 或 BYTE 数据的行时,首先创建简单大对象。在简单大对象写入磁盘之后,使用描述符更新行,并插入行。

简单大对象的删除或插入

数据库服务器无法修改简单大对象。它仅可以插入或删除它们。删除简单大对象意味着数据库服务器释放已删除对象所消耗的空间以再用。

更新 TEXT 或 BYTE 数据时,创建新的简单大对象,并使用新的 blob 描述符更新数据行。行的旧映象包含指向简单大对象的废旧值得描述符。将释放由废旧简单大对象所消耗的空间,用于提交更新之后的再使用。如果删除了包含其 blob 描述符的行,那么自动删除简单大对象。

简单大对象的大小限制

blob 描述符可以容纳的最大简单大对象是 (2312^{31} - 1) 或大约 2 千兆字节。

blobspace 页类型

每个 blobspace chunk 包含三种类型的项:

  • Blobspace 自由图页
  • 位图页
  • Blobpage

blobspace自由图页

blobspace 自由图页标识未使用的 blobpage ,以便数据库服务器可作为简单大对象创建的一部分来分配它们。分配 blobpage 时,将更新该页的自由图条目。简单大对象的所有条码都是链接的。

Blobspace 自由位图页是一个数据库服务器页的大小,自由图页上的每一个条目都是 8 字节,作为两个 32 位字进行存储,如下所示:

  • 第一字中的第一位指定 blobpage 是可用的还是已使用的。
  • 第一字中接下来的 31 位标识写入此 blobpage 时的当前逻辑日志文件。(该信息是记录 TEXT 或 BYTE 数据所必需的。)
  • 第二字包含与存储在该页上的简单大对象相关联的 tblspace 号。

可以适合自由图页的条目数依赖于您计算机的页大小。Blobspace chunk 中自由图页数依赖于 chunk 中 blobpage 的数量。

blobspace 位图页

blobspace 位图页跟踪 chunk 中 blobspace 自由图页的充满度和数目。每个 blobspace 位图页可以跟踪一定数量的位图页。Blobspace 位图页的大小取决于系统页的大小。如果系统大小为 2K ,blobspace 位图页可跟踪 2,032,128 个 blobpage 。如果系统页大小为 4K ,blobspace 位图页可以跟踪 8,258,048 个 blobpage 。

blobpage

blobpage 包含 TEXT 或 BYTE 数据。blobpage 大小由创建 blobspace 的数据库服务器管理要指定。blobpage 大小指定为页大小的倍数。

blobspace blobpage 的结构

用于在 blobspace 中存储简单大对象的存储策略不同于 dbspace 存储策略。数据库服务器不在单个 blobspace blobpage 上组合整个简单大对象或简单大对象的某些部分。例如:如果每个 blobspace blobpage 为 24 千字节,那么 26 千字节的简单大对象存储在两个 24 千字节的页上。额外的 22 千字节空间保持未使用。

blobpage 的结构包括 blobpage 头、 TEXT 或 BYTE 数据以及页结束时间戳记。blobpage 头除了其他信息还包含与数据行中转发指针相关联的页头时间戳记和 blob时间戳记。如果简单大对象存储在多个 blobpage 上,那么 blobpage 头中还包含下一 blobpage 的转发指针和另一个 blobpage 时间戳记。

sbspace 结构

sbspace 类似于 blobspace ,除了它拥有智能大对象外。

当 sbspace 在数据库创建时,它包含一个 sbspace 描述符。每个 sbspace chunk 包含以下结构:

  • Sbspace chunk 描述符
  • Chunk 可用页列表
  • Sbspace元数据区域(每个 chunk 最多一个)
  • 保留数据区域(每个 chunk 最多两个)
  • 用户数据区域(每个 chunk 最多两个)

为了获得最佳性能,建议元数据区域位于 sbspace 的中间。数据库服务器自动将元数据区域置于正确的位置。然而,要指定元数据区域的位置,请在 onspaces 命令中指定 -Mo 标志。

如果您未在 onspaces 命令的 -Ms 标志中指定元数据区域的大小,那么数据库服务器使用 AVG_LO_SIZE 的值(缺省值为 8千字节)计算元数据区域的大小。

下图说明了 sbspace 中 chunk 的结构,它是在 sbspace 创建之后立即显示的,每个保留区域可以分配给用户数据或元数据区域。保留其总是在 chunk 的用户数据区域中。

图: 一个简单的 sbspace chunk

由于图中的 chunk 是 sbspace 的一个 chunk ,所以它包含一个 sbspace 描述符。chunk 1 中的 chunk 描述符 tblspace 包含有关 chunk 1 和其后添加到 sbspace 中的所有块的信息。

元数据区域的结构

每个 sbspace 包含在其中 chunk 的元数据区域。

对于 chunk 头页,四个区域专用于 sbspace 中的第一 chunk :Sbspace 描述符 tblspace 、chunk 附件 tblspace 以及 1 级 和2 级压缩文档 tblspaces。Tblspace 头部分包含这些 tblspace 中的每一个 tblspace 头(特别的,tblspace tblspace 除外)。下图显示了单块 sbspace 中元数据的布局。

图: 单个 chunk sbspace 的元数据区域结构

在 oncheck -ps 选项中指定 Sbspace 名称时,可以显示分配并用于元数据区域中的每个 tblspace 的页数。

以下内容描述元数据区域是如何增长的:

  • sbspace 描述符 tblspace 不增长。
  • chunk 附件 tblspace 在添加 chunk 时增长。
  • LO 头 tblspace 在添加 chunk 时增长。
  • 如果 chunk 中的可用空间已大量分片,那么用户数据可用列表的 tblspace 增长。

sbpage 结构

每个 sbpage 由三个元素组成:sbpage 头、实际用户数据和 sbpage 跟踪器。 下图显示了 sbpage 的结构。Sbpage 头由标准页头构成。sbpage 跟踪器用于检测页上的不完全写入和检测页毁坏。

图: sbpage 结构

时间戳存储

数据库服务器使用时间戳记来标识事件对于同一类型的其他事件发生时的时间。时间戳记不是引用特定小时、分钟或秒的字面时间。它是数据库顺序指定的 4 字节整数。

数据库和表的创建:磁盘上发生什么

本节解释数据库服务器如何存储于数据库或表的创建相关的数据以及如何分配存储数据所必需的磁盘结构。

数据库的创建

在 root dbspace 存在之后,用户可以创建数据库。以下各段描述当数据库服务器添加新的数据库时磁盘上所发生的主要事件。

对系统目录表的磁盘空间分配

数据库服务器搜索 dbspace 中的 chunk 可用列表页,以查找要在其中创建系统目录表的可用空间。接下来,对于每个系统目录表,数据库服务器分配 8 个连续页,即每个系统目录表的初始 extent 的大小。这些表是分别创建的,不一定以彼此邻接的方式驻留在 dbspace 中。它们可以位于不同的 chunk 中。当为每张表的初始 extent 找到足够的空间时,分配这些项,并更新相关联的 chunk 可用列表页。

对系统目录表的跟踪

数据库服务器跟踪在数据库 tblspace (驻留在 root dbspace 中)中新创建的数据库,描述该数据库的条目添加到 root dbspace 中的 数据库 tblspace 中。对于每个系统目录表,数据库服务器向构建数据库的 dbspace 中的 tblspace tblspace 添加一个一页的条目。下图说明了数据库 tblspace 条目和该数据库的 systables 系统目录表的位置之间的关系。

图: 新数据库

表的创建

在 root dbspace 存在并创建了一个数据库之后,具有必需 SQL 特权的用户可以创建数据库表。当用户创建表时,数据库服务器以名为 extent 的单位向表分配磁盘空间。以下各段描述当数据库服务器创建表并分配磁盘空间的初始 extent 时所发生的主要事件。

磁盘空间分配

数据库服务器搜索 dbspace 中的 chunk 可用列表页,以查找等于表的初始 extent 大小的连续可用空间。当找到足够空间时,分配这些页并更新相关联的 chunk 可用列表页。

如果数据库服务器无法在 dbspace 的任何地方找到足够的相邻空间,那么它向该表分配最大可用数量的相邻空间。如果分配是可能的,那么即使所分配的空间量小于所请求的量,也不会返回任何错误信息。如果无法分配最小 extent 大小,那么返回错误。(Extent 不能跨两个 chunk 。)

tblspace tblspace 中的条目

数据库服务器向此 dbspace 中的 tblspace tblspace 添加一个该表的一页项目。指定给该表的 tblspace 编号是从描述该表的 tblspace tblspace 中的逻辑页号派生出来的。

tblspace 编号标识 tblspace 所位于的 dbspace 。tblspace extent 可位于任何 dbspace chunk 中。

如果必须确切知道 tblspace extent 的位置,请执行 oncheck -pe 命令,以获得按 chunk 排列的 dbspace 布局列表。

系统目录表中的条目

表本身是在数据库系统目录表中所存储的条目中完全描述的。每张表都指定由表标识或 tabid 。数据库中第一个用户定义的表对象的 tabid 值总是为 100 。

表可以位于与包含数据库的 dbspace 不同的 dbspace 中。Tblspace 本身是所分配 extents 的总和,而不是空间的单个连续分配,数据库服务器跟踪 tblspace 而不依赖于数据库。

临时表的创建

创建临时表所涉及的任务类似于数据库服务器添加新的永久表时所执行的任务。主要区别在于临时表不接收数据库的系统目录中的条目。