【数据库设计与实现】第1章:空间管理与数据布局

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 空间管理与数据布局 设计原则数据库设计数据布局和空间管理应当考虑哪些因素呢?又有哪些设计原则?本章先提出问题,看有哪些因素要考虑,然后选取Oracle和MySQL这2款最流行的数据库,看看它们是如何进行空间管理的。我们先看看有哪些因素要考虑:数据最终要反映到持久设备上,空间管理首先要考虑持久设备(如磁盘)的物理特性,考虑如何组织数据才能最大化地发挥存储设备的效率;如何协调平衡多样化的数据,如超大的
空间管理与数据布局 
设计原则

数据库设计数据布局和空间管理应当考虑哪些因素呢?又有哪些设计原则?本章先提出问题,看有哪些因素要考虑,然后选取OracleMySQL2款最流行的数据库,看看它们是如何进行空间管理的。我们先看看有哪些因素要考虑:

  • 数据最终要反映到持久设备上,空间管理首先要考虑持久设备(如磁盘)的物理特性,考虑如何组织数据才能最大化地发挥存储设备的效率;
  • 如何协调平衡多样化的数据,如超大的单表和数据庞大的小表,持久数据和临时数据,系统管理数据和用户数据,索引数据和非索引数据等等;
  • 如何平衡数据的逻辑相关性和逻辑独立性,逻辑相关性要求将逻辑上相关的数据聚集在一起,提高联合访问的效率,而逻辑独立性又要求将逻辑上独立的数据独立存放,提高数据失效、迁移、变更的效率;
  • 如何平衡并发度和空间利用率,并发度要求尽可能将所有相关的持久化设备都调动起来,将设备能力尽可能均衡地用满,而空间利用率则要求尽可能紧凑地利用空间,避免空间区域和碎片,提高扫描效率;
Oracle 设计原理
Datafile 空间管理

Oracletablespace由若干个datafile组成,datafileextent为单位进行空间的申请和释放。可以这么说,datafile是空间的提供者,而segment是空间的使用者,两者之间的交互语言就是extentblock

图1.2-1 Block结构

 

表1.2-1 Cache Layer结构

长度

含义

type

1

Block的类型,可以取值:

  • 0x01 undo segment header
  • 0x02 undo block
  • 0x03 save undo header block
  • 0x04 save undo data block
  • 0x05 data segment header block(temp, index, data)
  • 0x06 KTB managed data block(with ITL)
  • 0x07 temp table data block(no ITL)
  • 0x08 sort key
  • 0x09 sort run
  • 0x0a segment free list block
  • 0x0b data file header
  • 0x0c data segment header with FLG blcks
  • 0x0e unlimited undo segment header
  • 0x0f unlimited save undo segment header
  • 0x10 unlimited data segment header
  • 0x11 unlimited data segment header with FLG blocks
  • 0x12 extent map block
  • 0x17 bitmapped segment header
  • 0x1d KTFB bitmapped file space header
  • 0x1e KTFB bitmapped file space bitmap
  • 0x20 first level bitmap block
  • 0x21 second level bitmap block
  • 0x22 third level bitmap block
  • 0x23 pagetable segment header block
  • 0x24 pagetable extent map block
  • 0x25 system managed undo extent map block

frmt

1

格式,标识不同的block版本

spare1/2

2

保留

rdba

4

相对block地址,前10bit为相对文件id,后22bitblock号,可见1tablespace可以有1023datafile,每个datafile可以有4Mblock

scn

6

block最近一次更新时的scn

seq

1

如果更新本blockscn相同,则seq1

flg

1

组合标志位:

  • 0x01  block data 部分为空;
  • 0x02 delayed logging change advance SCN/SEQ
  • 0x04  校验 CHECKSUM
  • 0x08  临时 block

chkval

2

flgCHECKSUM标志为真时,写入前对block计算CHECKSUM,并填入本域,后继读出时会再次计算并检查,防止块损坏

spare3

2

保留

表1.2-2 footer结构

长度

含义

seq

1

等于cache layer中的seq

type

1

等于cache layer中的type

filter

2

数据文件:等于cache layerscn的末尾2byte

控制文件:control seq

block是数据管理的基本单元,在讨论datafile空间管理方式之前,我们先讨论一下block。如图1.2-1所示,所有的block都有3个部分组成:

  • Cache layer :定义block 的总体信息,详情如表1.2-1 所示;
  • Data block 中存放的内容,具体内容随cache layer 中的type 不同而不同;
  • Footer :如果block 发生了更改,scn seq 至少有一个会变动,通过比较footer cache layer 中的对应部分就可以检测块损坏(如写入磁盘时,写入一半掉电的情况),当然cache layer 中还有chkval ,如果启用可以提供更强的校验能力;

图1.2-2 datafile文件结构

 

了解了block基本文件结构之后,我们开始讨论datafile是如何提供空间的。如图1.2-2所示,datafileData File HeaderKTFB Bitmapped File Space HeaderKTFB Bitmapped File Space BitmapData组成,其中Data File HeaderKTFB Bitmapped File Space HeaderKTFB Bitmapped File Space Bitmap为文件保留区,保留区占用的block数随db_block_size的变化而变化(2KB保留32block4KB保留16block8KB保留8block16KB32KB保留4block),下面详细看下各个部分的含义:

  • Data File Header :描述本datafile 的总体信息,Cache Layer.type=0x0b block size 8KB 时占用2 block ,详情见表1.2-3
  • KTFB Bitmapped File Space Header :描述bitmap 的总体信息,Cache Layer.type=0x1d block size 8KB 时占用1 block ,详情见表1.2-4
  • KTFB Bitmapped File Space Bitmap :完整的bitmap ,用于描述本datafile 中各个extent 的详细情况,Cache Layer.type=0x1e block size 8KB 时占用5 block ,详情见表1.2-5
  • Data :用于存放具体数据;

表1.2-3 Data File Header部分关键信息

含义

dbid

本文件归属的db id

dbname

本文件归属的db name

tablespace

本文件归属的tablespace

file number

本文件的文件编号(dbauba等地址中都会含文件编号)

prev file

归属于同1tablepace的前1datafile

file size

本文件的大小

file type

本文件的类型,3表示数据文件

blksize

block的大小

checkpoint

checkpoint系统信息

backup

backup系统信息

表1.2-4 KTFB Bitmapped File Space Header部分关键信息

含义

RelFno

相对文件编号

Unit

单元数,即bitmap中每个bit位代表的block

Size

datafile包含的block

AutoExtent

对应于create tablespace语法

MaxSize

对应于create tablespace语法

tail

本文件最后1block

first

本文件第一个处于free状态的unit地址

free

free状态的unit数量

表1.2-5 KTFB Bitmapped File Space Bitmap部分关键信息

含义

beginblock

存放datablock地址,前面的区域存放Data File   Header、KTFB Bitmapped File Space Header、KTFB Bitmapped File Space Bitmap

flag

0永久文件,1临时文件

first

block中第1个可用的unit位置

free

blockfreeunit数量

map

1bit代表1unit0表示free1表示used

KTFB Bitmapped File Space Bitmap Block中,对于统一尺寸的extent来说,unit等于extent,即1bit位代表1extent。对于自动管理来说,extent的大小是变化的,1bit位代表1个最小尺寸的extent。由于大extent一定是小extent的整数倍,所以unit将最小exent作为基准,即1bit位代表64K。当extent的实际大小是1M8M64M时就用多个bit位来表示,如1Mextent就用连续的16bit来标识。

从空间利用率来看,由于某个extent只能属于某个特定的segment,所以小extent空间利用率高,大extent空间利用率低。例如当extent的大小为64M时,表哪怕仅使用了1个字节,也为它分配164Mextent,这64MB空间完全属于这个表,其它表无法使用。从性能的角度来看,大的extent空间比较连续,非常适合全表扫描类操作。Oracle的动态管理方式在空间利用率、性能之间做了平衡。

Segment 空间机制

图1.2-3 segment 3级bitmap管理机制

 

通过上节我们知道,datafile是通过bitmap管理表空间的extent分配情况。segment作为实际使用者,需要更加精确地知道本segment中各block的使用情况。如图1.2-3所示,segment是通过3级位图机制对block进行精细化管理的:

  • L1 BMB BitMap Block ):详细描述了其管理的各data block 的空间使用情况,并有指向其归属的L2 BMB 指针,详细情况见表1.2-6
  • L2 BMB :记录了其管理的所有L1 BMB 地址,并有指向其归属的L3 BMB 指针,详细情况见表1.2-7
  • L3 BMB :记录了其管理的所有L2 BMB 地址,并有指向其归属的segment header block 指针,实际上segment header block 本身就是一个特殊的L3 BMB

表1.2-6 L1 BMB部分关键信息

一级域

二级域

含义

parent dba

其归属的L2 BMB地址

unformatted

未格式化的block数量

total

MAPblock总数

first useful block

MAP中第1个可用的block

MAP(*n)

offset

extent的地址,即extent中首个block的地址

length

extentblock的数量

bits

标识extent中各个block的状态,每个block的状态占用4bit位:

  • 0000 unformatted ,尚未格式化;
  • 0001 full ,已满;
  • 0010 <25% ,空闲空间 <25%
  • 0011 25-50% ,空闲空间 25-50%
  • 0100 50-75% ,空闲空间 50-75%
  • 0101 >75 ,空闲空间 >75%
  • 0110 metadata ,元数据 block segment header block BMB 都是 metadata block

表1.2-7 L2 BMB部分关键信息

一级域

二级域

含义

parent dba

其归属的L3 BMB地址或segment   header block地址

number

MAPL1 BMB的数量

nfree

MAP中尚有空闲空间的L1 BMB数量

ffree

MAP中已满的L1 BMB数量

MAP(*n)

dba

L1 BMB的地址

free

5:空闲;

0FULL

随着申请的data block越来越多,需要不断地申请L1 BMBL2 BMBL3 BMB进行管理。实际上,通过L1 BMBL2 BMB已经能够管理非常庞大的data block数量,使用L3 BMB的情况非常少见(当然data segment header block本身就是一个特殊的L3 BMB)。在高并发时,存在多个L1 BMB可用,分散了争用,提高了并发性,可以获得非常高的性能:

  • 通过data segment header block 找到第1 个含空闲空间的L2 BMB L2 Hint for inserts );
  • 对操作进程PID HASH 运算,得到随机数N ,在L2 BMB 中找到第N L1 BMB;
  • 对操作进程PID HASH 运算,得到随机数M ,在L1 BMB 中找到第M 个有空闲空间的data block;
  • 向找到的data block 插入数据;

实际插入算法更加复杂,既要考虑一定的随机性和离散性,避免并发插入在特定的data blockBMB上竞争,又要考虑一定的聚集性,提高空间利用率和数据扫描效率(实际上会优先插入HWM以下的data block),最终算法在两者之间进行平衡。

图1.2-4 data segment header block结构

 

表1.2-8 Extent Control Header部分关键信息

一级域

二级域

含义

extents

segmentextent数量

blocks

segmentblock数量(不含segment header block

High HWM

HWM

High HWM的地址

ext

High HWM在哪个extent

blk

High HWM在该extent的哪个bock

ext size

High HWM所在的extent有多大

blocks below

segment中处于High   HWM下的block数量

Low HWM

HWM

Low HWM的地址

ext

Low HWM在哪个extent

blk

Low HWM在该extent的哪个bock

ext size

Low HWM所在的extent有多大

blocks below

segment中处于Low HWM下的block数量

L1 BMB for high HWM block

High HWM所在的block归属的L1 BMB

L1 BMB for low HWM block

Low HWM所在的block归属的L1 BMB

nl2

segmentL2 BMB的数量

blksz

block的大小

L2 array start offset

L2 Bitmap Mapsegment header block中的偏移

First level3 BMB

L3 BMB链表头

Last level3 BMB

L3 BMB链表尾

L2 hint for inserts

从本L2 BMB开始查找空闲空间供插入

Last level2 BMB

最新的L2 BMB

Last level1 BMB

最新的L1 BMB

表1.2-9 Extent Map和Auxiliary Map部分关键信息

一级域

二级域

含义

next

下一个map block的地址,随着extent数量的不断增长,data segment header block中就不够存放,这时会申请独立的maptype=0x12   extent map block)存放多出来的map

extents

extent的数量

Extent Map(*n)

dba

extent的地址

length

extentblock数量

Auxiliary Map(*n)

extent index

数组下标,虚拟列

L1 dba

管理该extentL1 BMB地址,1L1 BMB可以管理多个extent1extent只能归属于1L1 BMB管理

data dba

extent中首个data   block的地址,extent中可能有L1 BMBL2 BMBL3 BMBExtent   Map BlockSegment Header Block等等,这些Metadata Block一般处于extent的头部

如图1.2-4所示,data segment header block包含如下几个关键部分:

  • 通过extent control header L3 BMB L2 BMB L1 BMB 就可以知道所有data block 的空间使用情况、HWM 情况,然后进行高并发的插入操作;
  • 通过extent control header extent map auxiliary map 就可以知道所有数据的分布情况、HWM 情况,进行高效的数据扫描,即从extent map 起始extent 开始扫描,扫描至Low HWM ,对于Low HWM high HWM 之间的block ,需要参考L1 BMB ,以避开尚未格式化的block

图1.2-5 extent内block分布示例

 

最后再看一下extent内的block分布情况,不管block是何种类型,最终都要落到extent内,接受以extent为单位的连续空间管理。图1.2-5给出了extentblock的分布示例,如果extent内存在metadata类型的block,一般都存放在extent的头部。extent在使用和分配上存在如下规律:

  • 延迟分配,建表时不分配extent ,只有在实际插入数据时才会分配extent
  • 非统一大小时,extent 的大小是动态变化的(以block size 等于8K 为例):
    • 0-15 extent ,每个extent 包括8 block ,此时segment 总大小<=1M ,每个L1 BMB 可以管理16 block
    • 16-79 extent ,每个extent 包括128 block ,此时segment 总大小<=32M ,每个L1 BMB 可以管理64 block
    • 80-199 extent ,每个extent 包括1024 block ,此时segment 总大小<=1G ,每个L1 BMB 可以管理256 block
    • >199 extent ,每个extent 包括8192 block ,此时segment 总大小>1G ,每个L1 BMB 可以管理1024 block
  • 有些情况下1 L1 BMB 会管理多个extent ,所以有的extent 中没有L1 BMB ,有些情况下1 L1 BMB 无法将单个extent 中的所有block 都管理起来,此时extent 中就会有多个L1 BMB
  • tablespace 由多个datafile 组成时,extent 分片会考虑一定的均衡性,segment 会分布在多个datafile 中,但单个extent 不会跨datafile
Data Block 空间机制

图1.2-6 data block结构

 

表1.2-10 Table Directory部分关键信息

长度

含义

flag

1

N=pctfree hit(clusters)

F=don’t put on free list

K=flushable cluster keys

ntab

1

data block涉及的table数,只有clusters才可能大于1

nrow

2

data block中的记录数

frre

2

空闲行的位置,初始为0-1表示满了

fsbo

2

Free space的起始偏移

fseo

2

Free space的结尾偏移

avsp

2

Data block中空闲空间大小

tosp

2

所有事务提交后总可用空间大小

表1.2-11 Row Directory部分关键信息

长度

含义

offs

1

clusters表时有效

nrow

1

1个表的行数

rowoff*n

2

Array,每行记录占1个位置,记录改行记录在Row Data中位置。记录在Row   Directory中的下标是RowID组成部分之一

RowId=Seg/Obj Number + File Number + Block Number + Row Number,其中Row Number就是Row   Directory中的下标

表1.2-10 Row Data部分关键信息

长度

含义

fb

1

K=cluster key

C=cluster table member

H=head piece of row

D=deleted row

F=first data piece

L=last data piece

P=first column continues from previous piece

N=last column continues in next piece

  • 删除行时并不立刻删除,而是打上 D 标签,延后删除;
  • 行链接、行迁移,所以需要 H/F/L/P/N 等标签;

lb

1

本行记录被ITL中的哪个事务给锁住了

cc

1

记录的列数,超过255列就需要行链接

data

var

数据,每列数据由length+data组成,length的情况:

  • 0xff 表示 number 类型取值为 null ,没有 data 部分;
  • Length<=250 字节, length 占用 1 个字节;
  • Length>250 字节, length 占用 3 个字节( block 本身的大小不会超过 64K ),再长就采用行链接;

如图1.2-6所示,data block和数据存储强相关的部分主要包括Row DirectoryRow DataOracledata block设计有如下特点:

  • row directory :行目录,array 型结构,每行记录占用2 个字节,指向该行记录在Row Data 中的位置。array 的下标是RowID 的组成部分,所以某行记录一旦落到block 中,其在row directory 中的位置就不能改变(row data 是可以被整理的),因为index 、行迁移、行链接等都是通过RowID 来定位的;
  • row data :每行记录的头部大小应尽可能地小,从而提高空间利用率。fb lb cc 仅占用3 个字节,每列的length 部分也是变长的,且对于取值为null number 类型列,直接通过length=0xff 来表示,不再占用data 空间;
  • 随着行记录的增加,row directory 从上向下增长,row data 从下向上增长;
  • data block 如果写入过满,将来update 操作很可能产生较多行迁移,影响查询性能,为此通过PCTFree 参数定义插入时预留多少空间出来,用于将来的update pctfree data block ,以及B 树的leaf block 有效,但对B 树的root block branch block 无效);
数据布局

Oracle中有system tablesapcesysaux tablespacetemporary tablespaceundo tablespacepermanent tablespace,其存放的数据分别如下:

  • system tablespace :存放数据字典;
  • sysaux tablespace :存放工具相关对象信息;
  • temporary tablespace :存放临时数据,以及在内存不足时作为诸多活动的辅助空间(如排序);
  • undo tablespace :存放undo 日志(前像);
  • permanent tablespace :存放用户数据;

应用可以根据实际情况创建多个temporary tablespaceundo tablespacepermanent tablespace。同时还可以设置bigfile属性,以容纳更大的数据量。每个tablespace都按照segment进行管理,规则如下:

  • 1 个表创建1 segment ,如果是分区,每个分区创建1 segment
  • 1 个索引创建1 segment ,如果是分区索引,每个分区索引创建1 segment
  • 表的每个CLOB BLOB 或者NCLOB 列都会创建1 segment ,如果这些列上有索引,还会创建对应的LOB 索引segment
MySQL 设计原理
Datafile 空间管理

MySQL同样也采用了tablespacesegmentextentpage(对应oracle中的block)这几个概念,tablespace由若干个datafile组成,datafileextent为单位进行空间的申请和释放。不同的是MySQLextent分成了2种:

  • extent :正常的extent 1 extent 大小为1M ,由连续的page 组成,segment extent 为单位申请和释放空间;
  • frag extent :特殊的extent 1 frag extent 也是连续的1M 空间,但是frag extent 不属于任何segment ,而是为大家共用。MySQL 不支持变长extent ,为了节约空间,每个segment 的前32 page frag extent 中申请page ,超过32 page 再以extent 为单位申请空间;

图1.3-1 page结构

 

表1.3-1 FIL HEADER结构

长度

含义

FIL_PAGE_SPACE_OR_CHKSUM

4

4.0版本前存space id,之后存checksum

FIL_PAGE_OFFSET

4

page no

FIL_PAGE_PREV

4

B-Tree叶子page的前1page,用于索引扫描

FIL_PAGE_NEXT

4

B-Tree叶子page的下1page,用于索引扫描

FIL_PAGE_LSN

8

pageLSN,标识本page的最近一次修改

FIL_PAGE_TYPE

2

page类型:

FIL_PAGE_INDEX

FIL_PAGE_UNDO_LOG

FIL_PAGE_INODE

FIL_PAGE_IBUF_FREE_LIST

FIL_PAGE_TYPE_SYS

FIL_PAGE_FIL_FLUSH_LSN

8

  • 系统表空间:刷脏 page ,最近 1 次的 LSN ,本域仅在数据文件的第 1 page 中有效,用于判断数据库是否正常关闭;
  • 用户表空间:未使用;

FIL_PAGE_SPACE_ID

4

pagespace id

表1.3-2 FIL TAILER结构

长度

含义

FIL_CHECKSUM

4

pagechecksum,用于校验异常page

FIL_PAGE_LSN

4

等于FIL HEADER中的FIL_PAGE_LSN,用于检测page写一半系统掉电的异常情况

pageMySQL datafile空间管理的基本单位,其结构如1.3-1所示,组成部分如下:

  • FIL HEADER page 头,定义了page 的总体信息,详细情况见表1.3-1
  • Data :数据部分,格式随着FIL_PAGE_TYPE 不同而不同;
  • FIL TAILER page 尾,用于校验异常page ,详细情况见表1.3-2

图1.3-2 datafile总体空间布局

 

了解page的结构,下面看总体空间布局。如图1.3-2所示,MySQL数据文件空间布局相对比较固定,非常有规律可循:

  • FIL_PAGE_TYPE_XDES :该类page 存放extent 的管理信息,当page size 确定后每个FIL_PAGE_TYPE_XDES page 可以管理的extent 数量是固定的,这样本page 就可以按照管理的extent 数有规律地存放。图1.3-2 示例是page size 16K 的情况,每个FIL_PAGE_TYPE_XDES page 可以管理256 extent ,每个extent 包含64 page ,所以FIL_PAGE_TYPE_XDES page 每隔16384 256*64 )个page 出现1 个;
  • FIL_PAGE_TYPE_HDR FIL_PAGE_TYPE_HDR FIL_PAGE_TYPE_XDES 非常类似,除了存放extent 管理信息之外,还多了一个SPACE HEADER 结构,作为空间管理的总入口,可以这么说,FIL_PAGE_TYPE_HDR 是一个特殊的FIL_PAGE_TYPE_XDES 。本类page 只有1 个,且固定在第0 个位置上;
  • FIL_PAGE_IBUF_BITMAP :本类page 存放每个page 的空闲情况以及IBUF 的使用情况,由于FIL_PAGE_IBUF_BITMAP FIL_PAGE_TYPE_XDES 管理的规模一样多,所以FIL_PAGE_IBUF_BITMAP page 永远跟在FIL_PAGE_TYPE_XDES page 后面,位置固定;
  • FIL_PAGE_INODE :本类page 存放各segment 的入口信息,page 的类型为FIL_PAGE_INODE ,位置不固定;

图1.3-3 FIL_PAGE_TYPE_HDR vs FIL_PAGE_TYPE_XDES

 

表1.3-3 XDES Entry结构

长度

含义

XDES_ID

8

其归属的segment id

FLST_PREV

6

链表指针,指向前1XDES   Entry,前4个字节为该Entrypage no,后2个字节为page内偏移

FLST_NEXT

6

链表指针,指向后1XDES   Entry,前4个字节为该Entrypage no,后2个字节为page内偏移

XDES_XSTATE

4

表示本XDES Entry处在哪个链表上:

  • XDES_FREE FREE 链表;
  • XDES_FREE_FRAG FREE_FRAG 链表;
  • XDES_FULL_FRAG FULL_FRAG 链表;
  • XDES_FSEG :归属于 XDES_ID 记录的 segment

XDES_BITMAP

16

16*8,共计128bit位,每2bit位对应1page1bit标识该page是否为空(XDES_FREE_BIT),另1bit预留;

表1.3-4 SPACE HEADER结构

长度

含义

FSP_SPACE_ID

4

space id

FSP_NOT_USED

4

保留

FSP_SIZE

4

tablespacepage总数,自动扩展时会不断增加

FSP_FREE_LIMIT

4

小于本数的page都尚未初始化,该数以后的page都尚未加入到FREE LIST

FSP_SPACE_FLAGS

4

32bit位,各位的含义如下:

  • FSP_FLAGS_POS_ZIP_SSIZE :压缩 page size 0 表示非压缩;
  • FSP_FLAGS_POS_ATOMIC_BLOBS :行格式, compressed 或者 dynamic
  • FSP_FLAGS_POS_PAGE_SSIZE page size
  • FSP_FLAGS_POS_DATA_DIR :如果创建表空间显式指定了 data_dir ,设置本 flag
  • FSP_FLAGS_POS_SHARED :是否是共享的表空间;
  • FSP_FLAGS_POS_TEMPORARY :是否是临时表空间;
  • FSP_FLAGS_POS_ENCRYPTION :是否是加密表空间;
  • FSP_FLAGS_POS_UNUSED :未使用的位;

FSP_FRAG_N_USED

4

FSP_FREE_FRAG链表上已经被使用的page

FSP_FREE

16

链表指针,指向空extent(所有page都为空)链表

FSP_FREE_FRAG

16

链表指针,指向含空闲空间的frag extent链表

FSP_FULL_FRAG

16

链表指针,指向已经用满的frag extent链表

FSP_SEG_ID

8

当前系统最大segment id+1,作为分配segment   id的计数器

FSP_SEG_INODES_FULL

16

链表指针,指向完全用满的inode page链表

FSP_SEG_INODES_FREE

16

链表指针,指向尚有空闲空间的inode page链表

下面详细对比一下FIL_PAGE_TYPE_HDR pageFIL_PAGE_TYPE_XDES page,如图1.3-3所示,两者的结构基本是一样的。FIL_PAGE_TYPE_HDR pageSPACE HEADER结构是有信息的,而FIL_PAGE_TYPE_XDES page的对应位置为空。SPACE HEADER结构存放的是空间管理的总入口信息,所以只需要存在于第0page中。在讨论SPACE HEADER前,先看一下XDES Entry结构。如表1.3-3所示,XDES Entry通过XDES_BITMAP标识其管理的extent中各page的空间状态,FLST_PREVFLST_NEXT双向指针将处于相同状态且归属于同1segmentXDES Entry链接在一起。那么这些链表的头指针在哪里呢?在SPACE HEADER结构中,如表1.3-4所示,SPACE HEADER作为总入口,管理着如下5个重要的链表:

  • FSP_FREE 链表:管理所有空的extent ,指向状态为XDES_FREE XDES Entry
  • FSP_FREE_FRAG 链表:管理所有含空闲空间的frag extent ,指向状态为XDES_FREE_FRAG XDES Entry
  • FSP_FULL_FRAG 链表:管理所有已经写满的frag extent ,指向状态为XDES_FULL_FRAG XDES Entry ,随着frag extent 的满和不满,对应的XDES Entry 会在FSP_FREE_FRAG 链表和FSP_FULL_FRAG 链表之间移动;
  • FSP_SEG_INODES_FULL FSP_SEG_INODES_FREE 链表:分别管理所有已经写满和尚未写满的INDOES
  • 链表头结构:FLST_LEN 4 个字节+FLST_FIRST 6 个字节+FLST_LAST 6 个字节,共计16 个字节,FLST_LEN 表示链表长度,FLST_FIRST 指向第1 个节点(4 个字节的page no+2 个字节的page 内偏移),FLST_LAST 指向最后1 个节点;

通过FSP_FREE_FRAGFSP_FULL_FRAG链表将所有frag extent管理起来,通过FSP_FREE链表将所有尚未分配给segment的空闲extent管理起来,那么已经分配给segmentextent又是如何管理的呢?实际上,就是通过FSP_SEG_INODES_FULLFSP_SEG_INODES_FREE链表进行间接管理的,我们将在segment机制章节进一步讨论。

图1.3-4 FIL_PAGE_IBUF_BITMAP结构

 

表1.3-5 Change Buffer Bitmap结构

长度

含义

IBUF_BITMAP_FREE

2bit

某个page的空闲情况,0(0bytes)1(512bytes)2(1024bytes)3(2048bytes)

IBUF_BITMAP_BUFFERED

1bit

某个page上是否存在ibuf缓存

IBUF_BITMAP_IBUF

1bit

某个page本身是否是ibuf   BTree的节点

最后再看一下FIL_PAGE_IBUF_BITMAP pageMySQL发明了Insert Buffer机制,并将其进一步通用化为Change Buffer机制。其核心思想是对非唯一的二级索引进行insertdelete时,如果对应的page不在缓存中,不必将该page调度进缓存进行实时操作,而是将insertdelete操作缓存到insert buffer page中,待将来读到该page或者后台purge线程再实施真正的insertdelete操作,从而提高效率。但insert buffer机制存在如下约束和要求:

  • 唯一索引上的insert 操作不能缓存,因为要做唯一性校验,必须读到真正的page 才能做唯一性校验;
  • insert buffer 是以BTree 组织的,缓存的每条记录的主键为spaceid page no counter ,通过spaceid page no 记录缓存的操作时针对哪个page 的,但这就要求page no 在缓存过程中不能发生变化,这就需要一个机制来及时识别page no 是否可能发生变化;
  • 还需要一个机制来识别某个page 上的操作是否有缓存,从而在读到该page 时,先将缓存的操作merge 进来,然后再实施真正的读处理;

FIL_PAGE_IBUF_BITMAP page就是为这些目的而设计的,FIL_PAGE_IBUF_BITMAP page固定在FIL_PAGE_TYPE_XDES page后面。如图1.3-4所示,change buffer bitmap中每4bit对应后面的1page8192个字节就可以管理16384page8192*8/4)。如表1.3-5所示,4bit的组成如下:

  • IBUF_BITMAP_FREE :给出某个特定page 的空闲情况,如果空闲空间过小,会发生page 分裂,page no 会发生变化,不能缓存,否则可以缓存;
  • IBUF_BITMAP_BUFFERED :标识某个特定page 上是否做了操作缓存;
  • IBUF_BITMAP_IBUF :标识某个特定page 本身缓存的一部分;
Segment 空间机制

图1.3-5 FIL_PAGE_INODE page结构

 

表1.3-6 INODE Entry结构

长度

含义

FSEG_ID

8

INODE归属的segment0表示未使用

FSEG_NOT_FULL_N_USED

8

FSEG_NOT_FULL链表上已被使用的page

FSEG_FREE

16

链表头,指向已分配给本segment,但尚未使用的extent链表

FSEG_NOT_FULL

16

链表头,指向属于本segment,但尚未用满的extent链表

FSEG_FULL

16

链表头,指向属于本segment,且已完全用满的extent链表

FSEG_MAGIC_N

4

仅在调试模式下使用

FSEG_FRAG_ADDR

128

32*4,管理32frag page(分布在frag   extent中的page),4个字节记录page no

MySQL是通过INODE Entry管理segment的,每个INODE Entry对应1segment。下面结合存放INODE EntryFIL_PAGE_INODE page一起来讨论。如图1.3-5所示,FIL_PAGE_INODE page包括如下2个部分:

  • FSEG_INODE_PAGE_NODE 12 个字节的双向指针,将相关的FSEG_INODE_PAGE_NODE page 链接在一起。实际上有2 FSEG_INODE_PAGE_NODE 链表,就是FIL_PAGE_TYPE_HDR page 中的FSP_SEG_INODES_FULL FSP_SEG_INODES_FREE 链表,前者将所有已经写满INODE Entry FSEG_INODE_PAGE_NODE page 链接在一起,后者将尚未写满INODE Entry FSEG_INODE_PAGE_NODE page 链接在一起;
  • INODE Entry 1 FSEG_INODE_PAGE_NODE page 中可以存放n INODE Entry (随page 的大小变化),每个INODE Entry 管理1 个具体的segment

如表1.3-6所示,INODE Entry管理着1个具体的segment,其中的关键信息如下:

  • FSEG_FREE FSEG_NOT_FULL FSEG_FULL 3 extent 链表的指针头,结合XDES Entry 结构中的双向指针,把已经分配给本segment extent 按照尚未使用、已使用但尚未用满、已经用满3 种情况管理起来;
  • FSEG_FRAG_ADDR :通过记录page 号,将frag extent 中分配给本segment 32 page 管理起来;

图1.3-6 空间管理全貌

 

至此,如图1.3-6所示,我们得到MySQL空间管理的全景图(不含ibuf):

  • SPACE HEADER 中的FSP_FREE 结合XDES Entry 将所有尚未分配给segment extent 管理起来;
  • SPACE HEADER 中的FSP_FREE_FRAG FSP_FULL_FRAG 结合XDES Entry 将所有尚未用满和已经用满的frag extent 管理起来;
  • SPACE HEADER 中的FSP_SEG_INODES_FREE FSP_SEG_INODES_FULL 结合FSEG_INODE_PAGE_NODE 将所有尚未用满和已经用满的FIL_PAGE_INODE 管理起来;
  • 每个segment 1 INODE Entry (存在于FIL_PAGE_INODE 中),通过FSEG_FULL FSEG_NOT_FULL FSEG_FREE 结合XDES Entry 将所有分配给本segment 的已经用满、尚未用满、尚未使用的extent 管理起来;
  • frag extent 既被SPACE HEADER 管理,其中的page 同时又被INODE Entry 中的FSEG_FRAG_ADDR 管理;
Data Page 空间机制

图1.3-7 data page结构

 

表1.3-7 PAGE HEADER结构

长度

含义

PAGE_N_DIR_SLOTS

2

page directory区域的槽位数量

PAGE_HEAP_TOP

2

堆中空闲空间的偏移量

PAGE_N_HEAP

2

堆中记录的数量,包括用户记录、系统记录、标记为删除的记录,同时第1bit位为1时表示记录格式为compact

PAGE_FREE

2

指向第1条标记为删除的记录,记录头有next,可以将所有标记为删除的记录链接在一起

PAGE_GARBAGE

2

标记为删除的记录总空间(行记录的delete flag1),属于可回收的空间

PAGE_LAST_INSERT

2

指向最近1次插入的记录,用于优化顺序插入

PAGE_DIRECTION

2

最后1条记录的插入方向:

  • PAGE_LEFT
  • PAGE_RIGHT
  • PAGE_SAME_REC
  • PAGE_SAME_PAGE
  • PAGE_NO_DIRECTION

标识当前记录的插入顺序,用于插入优化

PAGE_N_RECS

2

以相同方向连续插入记录的数量

PAGE_MAX_TRX_ID

8

page内有效用户记录数,不含系统记录和标记为删除的记录

PAGE_LEVEL

2

当前pageBTree中的层级,叶子节点取值为0

PAGE_INDEX_ID

8

索引id,本page属于哪个索引

表1.3-8 segment info结构

长度

含义

FSEG_HDR_SPACE

4

segment对应的inode   entry所在pagespace id

FSEG_HDR_PAGE_NO

4

segment对应的inode   entry所在pagepage no

FSEG_HDR_OFFSET

2

segment对应的inode   entry在所在page内偏移

如图1.3-7所示,data page除了通用的FIL HEADERFIL TAILER之外,其它关键组成部分如下:

  • PAGE HEADER :描述了本page 的总体信息,详细见表1.3-7 ,通过PAGE_FREE 和每条记录中的REC_NEXT ,将所有标志为删除的记录链接在一起;
  • SEGMENT INFO :仅在BTree root page 中设置,SEGMENT INFO1 记录叶子节点segment 对应的INODE 信息,SEGMENT INFO2 记录非叶子节点segment 对应的INODE 信息;
  • SYS RECORDS 2 条特殊的系统记录,infimum supremun ,占用26 个字节,用于MySQL 特有的边界定位和锁控制;
  • USER RECORDS :用户记录,从上向下增长;
  • PAGE DIRECTORY :目录,从下向上增长,每个slot 占用2 个字节,指向USER RECORDS 中的具体某条记录。目录中的slot 和记录不是一一对应的,每4 8 条记录在目录中占用1 slot

有效的用户记录(删除标志位不为真)和2条系统记录通过记录头的REC_NEXT链接在一起,链接的顺序即为索引的键值顺序,且infimum永远是第1条记录,而supremum永远是最后1条记录。为了加快记录匹配效率,MySQLpage的底部设计了DIRECTORY区域,每隔4-8条记录占用1slotslot对应多少条记录是动态变化的,slot之间也不相等,就某个slot来说,通过对应记录头的REC_NEW_N_OWNED记录相应的记录数)。由于DIRECTORY区域是有序的(按主键或索引键逆序存放),可以通过折半查找快速匹配到目标记录。

图1.3-8 compact记录格式

 

表1.3-9 RECORD HEADER结构

长度

含义

REC_NEW_INFO_BITS

4bits

仅使用了前2bit1bit位标记本行记录是否已经被删除,另1bit位标记本行记录是否为BTree当前Level最左边page的第1条用户记录

REC_NEW_N_OWNED

4bits

0表示本行记录在page   directory中占1slot,具体取值为本slot和下1slot之间的记录数

REC_NEW_HEAP_NO

13bits

本行记录在堆中的序号,用于MySQL的锁机制

REC_NEW_STATUS

3bits

记录的类型:

  • REC_STATUS_ORDINARY :叶子节点记录;
  • REC_STATUS_NODE_PTR :非叶子节点记录;
  • REC_STATUS_INFIMUM infimum 系统记录;
  • REC_STATUS_SUPREMUM supremum 系统记录;

REC_NEXT

16btis

指向本page中的下1条记录,用于2中情况:

  • 有效记录:按键值顺序将本 page 内所有有效记录链接在一起;
  • 无效记录:将本 page 内所有标记为删除的记录链接在一起;

compact格式已经成为MySQL的主流格式。如图1.3-8所示,compact记录格式包括如下组成部分:

  • RECORD_HEADER :记录的头部信息,详情如表1.3-9 所示,记录在page 内的偏移一般都是指RECORD HEADER 的位置,因为记录的其它几个部分都是变长的;
  • VAR_COL_LEN_LST :每个变长列的实际长度在此描述,最大长度小于255 或者实际长度小于128 1 个字节,否则占2 个字节;
  • NULL_BITS :每个可为NULL 的列在此占1 bit ,如果列的实际值为NULL ,此bit 位为真,ROW_DATA 部分不会出现此列;
  • ROW_DATA :实际列数据,聚集索引会增加事务id 6 个字节)和回滚指针(7 个字节)2 个隐藏列;
数据布局

MySQL的数据包括系统数据、临时数据、回滚数据、用户数据、重做数据和binlog数据,重做数据和binlog数据相对独立,和tablespace没有太大关系,下面重点看其它几个数据的布局:

  • 用户数据:InnoDB 的所有表都是索引组织表,每个索引创建2 segment 1 segment 存放叶子节点page 1 segment 存放非叶子节点page 。每张表存放的tablespace 随着历史的演进有3 种方案:
    • 早期版本:所有数据都存放在1 个公共的系统tablespace 中;
    • 其后版本:增加支持每张表有1 个独立的tablespace 中;
    • 近期版本:增加支持通用的tablespace
  • 系统类数据(InnoDB ):主要有数据字典数据和系统数据,存放在公共的系统tablespace 中。字典数据表有SYS_TABLES SYS_INDEXS SYS_COLUMNS SYS_FIELDS ,分别存放表信息、索引信息、表列信息、索引列信息,也采用索引组织表方式存放。系统数据有insert buf double write 、事务系统数据等等;
  • 临时数据:存放用户创建的临时表,对应临时tablespace
  • 回滚数据:存放回滚数据,包括rollback segment undo log segment ,早期版本存放在公共的系统tablespace 中,近期版本可存放在独立的undo tablespace 中;
总结与分析

OracleMySQL的空间布局总体上非常类似,采用tablespacesegmentextentblockpage 4层管理机制。extentblockpage)最大化地发挥持久设备的物理特性,tablespacesegment用于在逻辑上平衡数据的独立性和相关性。不过在管理设计上,OracleMySQL还是存在非常大的差异性。

blockpage)层面,Oracleblock设计更加通用,MySQLpage设计与索引组织表深度耦合,具体表现在:

  • 对于单条记录,MySQL 设计了NULL_BITS ,稀疏场景下可以有效节省空间。不过MySQL 的记录头和隐藏列比较厚重,每条记录占用18 个字节(RECORD HEADER 5 个字节,事务id 6 个字节,回滚指针占7 个字节),Oracle 的记录头仅占3 个字节;
  • MySQL page 也设计相对比较粗放,某些区域仅在特定场景下有效,如SEGMENT INFO 仅在BTree root page 中有效,FIL_PAGE_PREV FIL_PAGE_NEXT 仅对BTree 的叶子节点page 有效等等;
  • Oracle 采用了相对地址管理方式,RowID 中保存了file no block no directory id ,优势是可以快速定位记录,缺点是block 内的碎片整理可以比较高效,但block 间的整理涉及记录在block 间移动,代价非常高(shrink table ,调整rowid ,涉及面较广) MySQL 采用的是主键管理方式,数据和索引解耦,优势是不仅可做page 内的碎片整理,还可以做page 间的碎片整理(optimize table ),缺点是定位记录需在BTree 中检索,然后在page 内通过directory 进行折半查找,定位效率低;
  • Oracle page 组织方式上,记录之间没有强的依赖关系,插入操作可以并发执行,并发间竞争小。MySQL 是索引组织的,插入操作竞争page 的概率大,且对于每个插入操作而言,需要在directory 中进行这边查找,且有可能发生directory 目录重组,单次插入操作的平均成本也相对较高;

extent层面,Oracle通过变长extent应对多样化的表大小,MySQL则通过frag extent来达到类似的效果。不过extentblock的管理上,Oracle做得更加精细,也更加准确。采用4bit描述1block,区分<25% free25-50% free50-75% free>75% freeMySQL只使用了1bit(虽然预留了2bit),只能描述1page满还是空。当然MySQL还有1change buffer机制,为了获得好的缓存效果,也统计了page的空间情况,但也只区分了0 free512 free1024 free2048 free,完全针对change buffer机制定制,在两处对page进行了各自的统计,并没有拉通设计。

segment层面,Oracle采用三级位图进行管理,实际上L1 BMB已经达到block级,和extentblock的管理是拉通的。MySQL则通过3个双向链表FSEG_FREEFSEG_NOT_FULLFSEG_FULL1FSEG_FRAG_ADDR位图进行管理。实际上,Oracle刚开始也采用的链表方式管理,然后演进到位图方式。链表管理方式需要从链表头开始进行遍历,高并发下竞争非常明显,影响并发效率。当然MySQL在并发插入时瓶颈在索引组织表上,此处的瓶颈还没有显现出来。

segment的使用上,两者都区分undo segmenttemporary segmentOracle将大字段(BLOB)放在独立的segment中,表数据和索引逻辑独立,所以也分别放在各自的segment中。MySQL是索引组织表,并将索引的叶子节点和非叶子节点分别放在2个不同的segement中。

tablesapce层面,都区分permanent tabletemporary tablespaceundo tablespace,两者没有太大的本质区别。

PDF版下载地址:http://blog.itpub.net/69912723/viewspace-2713926/

相关文章
|
8月前
|
缓存 Oracle 关系型数据库
【数据库设计与实现】第1章:空间管理与数据布局
空间管理与数据布局 设计原则数据库设计数据布局和空间管理应当考虑哪些因素呢?又有哪些设计原则?本章先提出问题,看有哪些因素要考虑,然后选取Oracle和MySQL这2款最流行的数据库,看看它们是如何进行空间管理的。我们先看看有哪些因素要考虑:数据最终要反映到持久设备上,空间管理首先要考虑持久设备(如磁盘)的物理特性,考虑如何组织数据才能最大化地发挥存储设备的效率;如何协调平衡多样化的数据,如超大的
【数据库设计与实现】第1章:空间管理与数据布局
|
4天前
|
弹性计算 安全 API
访问控制(RAM)|云上安全使用AccessKey的最佳实践
集中管控AK/SK的生命周期,可以极大降低AK/SK管理和使用成本,同时通过加密和轮转的方式,保证AK/SK的安全使用,本次分享为您介绍产品原理,以及具体的使用步骤。
101786 0
|
4天前
|
SQL 关系型数据库 分布式数据库
Doodle Jump — 使用Flutter&Flame开发游戏真不错!
用Flutter&Flame开发游戏是一种什么体验?最近网上冲浪的时候,我偶然发现了一个国外的游戏网站,类似于国内的4399。在浏览时,我遇到了一款经典的小游戏:Doodle Jump...
|
12天前
|
弹性计算 运维 安全
访问控制(RAM)|云上程序使用临时凭证的最佳实践
STS临时访问凭证是阿里云提供的一种临时访问权限管理服务,通过STS获取可以自定义时效和访问权限的临时身份凭证,减少长期访问密钥(AccessKey)泄露的风险。本文将为您介绍产品原理,以及具体的使用步骤。
151035 4
|
10天前
|
数据采集 存储 运维
提升团队工程交付能力,从“看见”工程活动和研发模式开始
本文从统一工程交付的概念模型开始,介绍了如何将应用交付的模式显式地定义出来,并通过工具平台落地。
119990 57
|
11天前
|
监控 负载均衡 Java
深入探究Java微服务架构:Spring Cloud概论
**摘要:** 本文深入探讨了Java微服务架构中的Spring Cloud,解释了微服务架构如何解决传统单体架构的局限性,如松耦合、独立部署、可伸缩性和容错性。Spring Cloud作为一个基于Spring Boot的开源框架,提供了服务注册与发现、负载均衡、断路器、配置中心、API网关等组件,简化了微服务的开发、部署和管理。文章详细介绍了Spring Cloud的核心模块,如Eureka、Ribbon、Hystrix、Config、Zuul和Sleuth,并通过一个电商微服务系统的实战案例展示了如何使用Spring Cloud构建微服务应用。
103503 8
|
12天前
|
人工智能 Serverless 对象存储
让你的文档从静态展示到一键部署可操作验证
通过函数计算的能力让阿里云的文档从静态展示升级为动态可操作验证,用户在文档中单击一键部署可快速完成代码的部署及测试。这一改变已在函数计算的活动沙龙中得到用户的认可。
120843 218
|
11天前
|
SQL 存储 数据可视化
Ganos H3地理网格能力解析与最佳实践
本文介绍了Ganos H3的相关功能,帮助读者快速了解Ganos地理网格的重要特性与应用实践。H3是Uber研发的一种覆盖全球表面的二维地理网格,采用了一种全球统一的、多层次的六边形网格体系来表示地球表面,这种地理网格技术在诸多业务场景中得到广泛应用。Ganos不仅提供了H3网格的全套功能,还支持与其它Ganos时空数据类型进行跨模联合分析,极大程度提升了客户对于时空数据的挖掘分析能力。
|
11天前
|
存储 缓存 安全
深度解析JVM世界:JVM内存结构
深度解析JVM世界:JVM内存结构