Mysql innodb b树中的内部节点是如何物理存储的?

Mysql innodb b树中的内部节点是如何物理存储的?,mysql,tree,innodb,b-tree,Mysql,Tree,Innodb,B Tree,innodb中的非叶b树节点是如何物理表示的 回想一下,b-树(更具体地说是b+树)既有叶节点也有非叶节点。在b+树中,所有叶节点都位于非叶节点树或“内部”节点树下,并指向实际包含行数据的页面 我知道非叶节点存储在非叶节点段中,并使用类似于数据页的页面。我已经找到了大量关于数据页如何物理存储的文档,但是我还没有找到任何关于非叶索引页的内容。在《学习InnoDB:核心之旅》中,我介绍了InnoDB_图表项目来记录InnoDB内部,它提供了本文中使用的图表。稍后,在对innodb_ruby的快速介绍

innodb中的非叶b树节点是如何物理表示的

回想一下,b-树(更具体地说是b+树)既有叶节点也有非叶节点。在b+树中,所有叶节点都位于非叶节点树或“内部”节点树下,并指向实际包含行数据的页面


我知道非叶节点存储在非叶节点段中,并使用类似于数据页的页面。我已经找到了大量关于数据页如何物理存储的文档,但是我还没有找到任何关于非叶索引页的内容。

在《学习InnoDB:核心之旅》中,我介绍了InnoDB_图表项目来记录InnoDB内部,它提供了本文中使用的图表。稍后,在对innodb_ruby的快速介绍中,我介绍了innodb_space命令行工具的安装和一些快速演示

InnoDB索引页的物理结构在InnoDB索引页的物理结构中进行了描述。现在,我们将使用一些实际示例来研究InnoDB如何逻辑地构造其索引

术语旁白:B+树、根、叶和层 InnoDB的索引使用B+树结构。当数据不适合内存并且必须从磁盘读取时,B+树特别有效,因为它确保访问任何请求的数据都需要固定的最大读取次数,仅基于树的深度,可以很好地扩展

索引树从“根”页面开始,其位置是固定的(并永久存储在InnoDB的数据字典中),作为访问树的起点。该树可能与单个根页面一样小,也可能与多级树中数百万个页面一样大

页面被称为“叶”页面或“非叶”页面(在某些上下文中也称为“内部”或“节点”页面)。叶页包含实际的行数据。非叶页面仅包含指向其他非叶页面或叶页面的指针。树是平衡的,因此树的所有分支都具有相同的深度

InnoDB为树中的每个页面分配一个“级别”:叶页面被分配为级别0,级别向上递增。根页面级别基于树的深度。如果区分很重要,那么所有既不是叶页也不是根页的页面也可以称为“内部”页面

叶页和非叶页 对于叶页和非叶页,每条记录(包括下确界和上确界系统记录)都包含一个“下一条记录”指针,该指针存储到下一条记录的偏移量(在页面内)。链表从下确界开始,按键升序链接所有记录,以上确界结束。记录在页面内没有物理排序(插入时占用任何可用空间);它们唯一的顺序来自它们在链表中的位置

叶页包含非键值,作为每个记录中包含的“数据”的一部分:

非叶页具有相同的结构,但它们的“数据”不是非键字段,而是子页的页码,而不是确切的键,它们表示它们指向的子页上的最小键:

同一级别的页面 大多数索引包含多个页面,因此多个页面按升序和降序链接在一起:

每一页都包含“上一页”和“下一页”的指针(在FIL标题中),对于索引页,指针用于在同一级别上形成页面的双链接列表(例如,叶页,在0级上形成一个列表,在1级上形成一个单独的列表,等等)

单页表格的详细查看 让我们看一下在单个索引页中与B+树相关的大部分内容:

创建并填充表格 上图中使用的测试表可以创建并填充(确保您使用的是innodb_file_per_table并使用Barracuda文件格式):

虽然这个表非常小而且不现实,但它确实很好地演示了记录和记录遍历的工作原理

验证空间文件的基本结构 该表应该与我们之前检查过的内容相匹配,三个标准开销页(FSP_HDR、IBUF_BITMAP和INODE)后面是索引根的一个索引页,在本例中是两个未使用的分配页

$innodb_space-f t_btree.ibd空间页类型区域

space index pages summary(空间索引页面摘要)模式将为我们提供每页中的记录计数,并显示预期的3条记录:

$innodb_空间-f t_btree.ibd空间索引页摘要

(请注意,space index pages summary还将分配的空页面显示为零记录的空页面,因为这通常是出于打印目的而感兴趣的。)

“空间索引”模式将显示主键索引的统计信息,主键索引消耗其内部文件段上的单个页面:

$innodb_space-f t_btree.ibd空间索引

设置记录描述符 为了让innodb_ruby解析记录的内容,我们需要提供一个记录描述符,它只是一个ruby类,提供一个返回索引描述的方法:

类SimpleTBTreeDescriber 我们需要注意,这是聚集键,提供键的列描述,以及非键(“行”)字段的列描述。有必要要求innodb_space使用以下附加参数加载此类:

-r-r./简单树描述器.rb-d简单树描述器

查看记录内容 反渗透
 CREATE TABLE t_btree (
  i INT NOT NULL,
  s CHAR(10) NOT NULL,
  PRIMARY KEY(i)
) ENGINE=InnoDB;

INSERT INTO t_btree (i, s)
  VALUES (0, "A"), (1, "B"), (2, "C");
start       end         count       type                
0           0           1           FSP_HDR             
1           1           1           IBUF_BITMAP         
2           2           1           INODE               
3           3           1           INDEX               
4           5           2           FREE (ALLOCATED)  
page        index   level   data    free    records 
3           18      0       96      16156   3       
4           0       0       0       16384   0       
5           0       0       0       16384   0   
id          root        fseg        used        allocated   fill_factor 
18          3           internal    1           1           100.00%     
18          3           leaf        0           0           0.00%  
{:format=>:compact,
 :offset=>125,
 :header=>
  {:next=>157,
   :type=>:conventional,
   :heap_number=>2,
   :n_owned=>0,
   :min_rec=>false,
   :deleted=>false,
   :field_nulls=>nil,
   :field_lengths=>[0, 0, 0, 0],
   :field_externs=>[false, false, false, false]},
 :next=>157,
 :type=>:clustered,
 :key=>[{:name=>"i", :type=>"INT", :value=>0, :extern=>nil}],
 :transaction_id=>"0000000f4745",
 :roll_pointer=>
  {:is_insert=>true, :rseg_id=>8, :undo_log=>{:page=>312, :offset=>272}},
 :row=>[{:name=>"s", :type=>"CHAR(10)", :value=>"A", :extern=>nil}]}
ROOT NODE #3: 3 records, 96 bytes
RECORD: (i=0) -> (s=A)
RECORD: (i=1) -> (s=B)
RECORD: (i=2) -> (s=C)
ROOT NODE #3: 2 records, 26 bytes
NODE POINTER RECORD >= (i=252) -> #36
INTERNAL NODE #36: 1117 records, 14521 bytes
NODE POINTER RECORD >= (i=252) -> #4
LEAF NODE #4: 446 records, 9812 bytes
RECORD: (i=1) -> ()
RECORD: (i=2) -> ()
RECORD: (i=3) -> ()
RECORD: (i=4) -> ()
NODE POINTER RECORD >= (i=447) -> #1676
LEAF NODE #1676: 444 records, 9768 bytes
RECORD: (i=447) -> ()
RECORD: (i=448) -> ()
RECORD: (i=449) -> ()
RECORD: (i=450) -> ()
NODE POINTER RECORD >= (i=891) -> #771
LEAF NODE #771: 512 records, 11264 bytes
RECORD: (i=891) -> ()
RECORD: (i=892) -> ()
RECORD: (i=893) -> ()
RECORD: (i=894) -> ()
{:format=>:compact,
 :offset=>125,
 :header=>
  {:next=>11877,
   :type=>:node_pointer,
   :heap_number=>2,
   :n_owned=>0,
   :min_rec=>true,
   :deleted=>false,
   :field_nulls=>nil,
   :field_lengths=>[0],
   :field_externs=>[false]},
 :next=>11877,
 :type=>:clustered,
 :key=>[{:name=>"i", :type=>"INT UNSIGNED", :value=>252, :extern=>nil}],
 :child_page_number=>4}
Height  Non-leaf pages  Leaf pages  Rows    Size in bytes
1   0   1   468 16.0 KiB
2   1   1203    > 563 thousand  18.8 MiB
3   1204    1447209 > 677 million   22.1 GiB
4   1448413 1740992427  > 814 billion   25.9 TiB