InnoDB storage engine - table

1. Index Organized Tables

In InnoDB storage engine, a table is organized according to the order stored in the primary key table index which is referred tissue storage table.

In InnoDB storage engine, each table has a primary key, if no explicit definition of the primary key table creation will select or create a primary key field in the following manner:

  • If there is non-empty unique index, this field is selected as the primary key (if there are multiple indexes defined in order to select the first field)
  • If not the first item, automatically creates a 6-byte pointer.

2. InnoDB logical storage structure

From the logical storage configuration of the storage engine InnoDB See, all data is stored in a logical space, referred tablespace Table space and by the segment (segment), regions (extents), page (page, the default is 16K )composition

Here Insert Picture Description

(1). Tablespace

Table space can be seen as the highest level of the logical structure of the InnoDB storage engine, all data stored in the table space. If the user enables the parameters innodb_file_per_table, then each table can have a separate table space.

But note that each table is a separate table space only to store data, index, and insert buffer Bitmap page, other types of data (undo rollback information, insert buffer index page, the system transaction information, and so the second write buffer ) is stored in the shared table space. it means that, even if opened innodb_file_per_table parameters, or shared table space will continue to increase.

Space in the shared space table if the failure (e.g., overwrite the undo information), and does not recover the memory immediately, but is marked as free space for the next use.

(2) Segment

Table space is another segment consisting of a common segment has data segment, index segment, rollback segments, and so on.

InnoDB storage engine is an index of tissue, so that the data that is the index, i.e., data that is then the data segment B + tree leaf node, the index segment is the B + number of non-leaf nodes. Rollback more specific, temporarily introduced.

In the InnoDB storage engine, the management of the segment itself is done by the engine.

(3) The district

Page region is composed of a continuous space, in any case the size of each zone are 1MB, in order to ensure the integrity of the page area, InnoDB storage engine will apply for the disposable 4-5 zone from the disk. In the default next, the page size InnoDB storage engine is 16KB, i.e., a region 64 consecutive pages.

But this is not the 64 consecutive pages at the time of the application area after the completion of .InnoDB storage space to get the engine started in each district will use the 32-page fragment page size to store data, these pages will be used up time time application 64 consecutive pages. this is intended for small tables or undo such segments, may apply less space at the beginning of the disk capacity save money.

(4). Page

InnoDB page is the smallest unit of disk management, each default page size is 16KB. Starting InnoDB 1.2.x version, you can innodb_page_size the page size to 4K, 8K, 16K.

Common page types are:

  • Data page (B-tree Node)
  • undo found Page (undo Log Page)
  • System Page (System Page)
  • Transaction data page (Transaction system Page)
  • Insert page bitmap buffer (Insert Buffer Bitmap)
  • Insert buffer free list page (Insert Buffer Free List)
  • Uncompressed binary large object pages (Uncompressed BLOB Page)
  • Compressed binary large object page (compressed BLOB Page)

(5) Line

InnoDB storage engine is for a column, that is to say the data is stored in rows. Rows of each page is stored with a rigid definition, allows storage of up to 7992 rows (16KB / 2-200).

3. InnoDB rows format

InnoDB storage engine and most databases, records are stored row. Before InnoDB 1.0.x version, the InnoDB storage engine offers two of the Compact and Redundant format to store data rows in MySQL 5.1 version, The default setting for the Compact version.

(1). Compact rows format

Compact rows really introduced in MySQL 5.0, which is designed to efficiently store data more rows of data stored in a page, the higher the performance of

Here Insert Picture Description

Compact row of variable-length record format field length list, NULL flag information recording heads, column data 1, data 2 ... Column composition.

Wherein the length of the list is a variable length field in accordance with the reverse order of columns, there are a number of 1 or 2 bytes binary composition (length 225 is represented in 1 byte, 2 bytes, compared with 65535). After a list of variable-length field length the second part is the NULL symbol for, but instead the data whether the line has a NULL value, display in the form of binary information followed by the recording head, the fixed station 5 bytes, the meaning of the following table:

name size description
() 1 unknown
() 1 unknown
delete_flag 1 Whether the row is deleted
min_rec_flag 1 1 is representative of the record previously defined as the smallest recording
n_owned 4 The record has a number of records
heap_no 13 Index heap sort of recording this record
record_type 3 Record Type: 000 representing an average, the number of Node B + 001 represents pointer 010 indicates Infimum, 011 denotes Supermum, 1xx reservations
next_record 16 The relative position of the next record in the page
Total 40

​  最后的部分就是存储每个列的数据,NULL不占该部分的任何空间.

​  每行数据除了用户定义的列外,还有两个隐藏列,事务ID列(6字节)和回滚指针列(7字节).如果InnoDB表没有定义主键,每行还会增加一个rowid列.

(2). Redundant行记录格式

​  Redundant是MySQL 5.0之前InnoDB的行记录存储方式,不同于Compact方式,首部是一个字段长度偏移列表,同样是逆序,然后是记录头信息,紧跟着列数据1,列数据2…

名称 大小 描述
() 1 未知
() 1 未知
delete_flag 1 该行是否已经被删除
min_rec_flag 1 如果为1,则该记录是预先被定义为最小的记录
n_owned 4 该记录拥有的记录数
heap_no 13 索引堆中该条记录的索引号
n_fields 10 记录中列的数量
1byte_offs_flag 1 偏移列表为1字节还是2字节
next_record 16 页中下一条记录的相对位置
Total 48

(3). 行溢出数据

​  InnoDB存储引擎可以将一条记录中的某些数据存储在真正的数据页之外,一般为BLOB,LOB这种大对象列类型会这样存储.但是需要注意的是,BLOB也可以不将数据放在溢出页面,VARCHAR也可能会存在溢出页面之中.

​  VARCHAR类型最大支持65535字节,所以对于不同的编码格式,存储的数据长度是不一致的.此外这个长度是对于一行中的所有列VARCHAR总长度和,如果这个总长度超出了65535字节,就发生了溢出,会将数据存放在Uncompress BLOB页中

Here Insert Picture Description
​  InnoDB存储引擎表是索引组织的,即B+Tree的结构,这样每个页中至少要存放两条数据才有意义,如果一行的大小不允许同一页中在存放下一行数据,那么这一行数据就会被存放入溢出页中.

​  对于TEXT和BLOB类型的数据,与VARCHAR一样.

​  大多数情况下,BLOB类型的数据都很大,都会溢出的,数据数据都是保存在BLOB页中的,数据页只保存前768字节.

(4). Compressed和Dynamic行记录格式

​  InnoDB 1.0.x版本开始引入了新的文件格式,成为Barracuda文件格式,有两种行记录格式:Compressed和Dynamic.这两种新的记录格式对于存放BLOB中的数据采用了完全的行溢出方式.

​  除此之外,Compressed行记录格式的另一个功能是存储在其中的行数据会以zlib的算法进行压缩.

(5). CHAR的行结构存储

​  从MySQL 4.1版本开始,CHR(N)中的N指的是字符的长度,而不是存储数据所占字节长度.也就是说不同的字符集下,CHAR类型存储的不是定长数据.

4. InnoDB数据页结构

​  页是InnoDB存储引擎管理数据库的磁盘最小单位,具体实例可参考MySQL技术内幕InnoDB存储引擎第二版P127,InnoDB数据页由一下7部分组成:

  • File Header(文件头)
  • Page Header(页头)
  • Infimun和Supermum Records
  • User Records(行记录)
  • Free Space(空闲空间)
  • Page Directory(页目录)
  • File Trailer(文件结尾信息)

Here Insert Picture Description

(1). File Header

​  File Header用来记录页的一些头信息,由以下8部分组成共38字节.

File Header组成部分:

名称 大小(字节) 说明
FIL_PAGE_SPACE_OR_CHKSUM 4 MySQL 4.0.14之前该值为0,之后代表该页的checksum值
FIL_PAGE_OFFSET 4 表空间中页的偏移值.
FIL_PAGE_PREV 4 当前页的上一页(B+数决定叶子节点必定是双向链表)
FIL_PAGE_NEXT 4 当前页的下一页
FIL_PAGE_LSN 8 代表该页最后被修改的日志位置LSN(Log Sequence number)
FIL_PAGE_TYPE 2 InnoDB存储引擎页的类型(0x45BF代表数据页)
FIL_PAGE_FILE_FLUSH_LSN 8 在系统表空间的页中定义,代表文件至少被更新到了该LSN值
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 4 从MySQL 4.1开始代表该页属于那个表空间

InnoDB存储引擎中页的类型:

名称 十六进制表示 解释
FIL_PAGE_INDEX 0x45BF B+数叶节点
FIL_PAGE_UNDO_LOG 0x0002 Undo log页
FIL_PAGE_INODE 0x0003 索引节点
FIL_PAGE_IBUF_FREE_LIST 0x0004 Insert Buffer空闲列表
FIL_PAGE_TYPE_ALLOCATED 0x0000 该页为最新分配
FIL_PAGE_IBUF_BITMAP 0x0005 Insert Buffer位图
FIL_PAGE_TYPE_SYS 0x0006 系统页
FIL_PAGE_TYPE_TRX_SYS 0x0007 事物系统数据
FIL_PAGE_TYPE_FSP_HDR 0x0008 File Space Header
FIL_PAGE_TYPE_XDES 0x0009 拓展描述页
FIL_PAGE_TYPE_BLOB 0x000A BLOB页

(2). Page Header

​ 该部分用来记录数据页的状态信息.由14部分组成,共56字节.

名称 大小(字节) 说明
PAGE_N_DIR_SLOTS 2 在Page Directory(页目录)中的Slot(槽)数
PAGE_HEAP_TOP 2 堆中第一个记录的指针,记录在页中的数据以堆的形式存放
PAGE_N_HEAP 2 堆中的记录数
PAGE_FREE 2 指向可重用空间的首指针
PAGE_GARBAGE 2 已删除记录的字节数
PAGE_LAST_INSERT 2 最后插入记录的位置
PAGE_DIRECTION 2 最后插入的方向(0x01,ox02,0x03,0x04,0x05)
PAGE_N_DIRECTION 2 一个方向上连续插入记录的数量
PAGE_N_RECS 2 该页中记录的数量
PAGE_MAX_TRX_ID 8 就当前页的最大事务ID
PAGE_LEVEL 2 当前页在索引数中的位置,0x00代表叶节点
PAGE_INDEX_ID 8 索引ID
PAGE_BTR_SEG_LEAF 10 B+树数据页非叶节点所在段的segment header.(仅在B+数的root页中被定义)
PAGE_BTR_SEG_TOP 10 B+树数据页所在段的segment header.(仅在B+数的root页中被定义)

(3). Infimum和Supremum Record

​  每个数据页中有两个虚拟的行记录,用来限定记录的边界.Infimum用来记录比页中任何主键值都要小的值,Supermum指比任何可能大的值还要大的值.这两个值在页创立时建立,任何情况下不会被删除

Here Insert Picture Description

(4). User Record和Free Space

​  User Record指实际存储行记录的内容.

​  Free Space指空闲空间,也是个链表数据结构.一条记录被删除后会被加入到空闲链表中.

(5). Page Directory

​  页目录,其中存放了记录的相对位置,有时候这些记录指针被称为Slots(槽).在InnoDB中并不是每个记录拥有一个槽,InnoDB存储引擎的槽是一个稀疏目录,一个槽中可能包含多个记录.

​  注意:B+树索引本身并不能找到具体的一条记录,能找到的知识该记录所在的页。数据库把页载入到内存,然后通过Page Directory再进行二叉查找

(6). File Trailer

​  为了检测页是否已经完整的写入磁盘,设置了File Trailer部分.

​  该部分只有一个FIL_PAGE_END_LSN部分,占用8字节.前4字节代表该页的checksum值,最后4字节和File Header中的FIL_PAGE_LSN相同.这两个值用于与File Header中的FIL_PAGE_SPACE_OR_CHKSUM和FIL_PAGE_LSN进行比较,依次来确保页的完整性.

​  默认情况下,每次从磁盘读取一个页就会检查依次该页的完整性,就是通过检查File Trailer部分进行检测.

5. Named File Formats机制

​  目的是解决不同版本下页结构兼容性问题.

​  InnoDB存储引擎不同版本之间新的文件格式总是包含于之前版本的页格式

Here Insert Picture Description

6. 约束

(1). 数据完整性

​  关系型数据库和文件系统的一个不同点就是关系数据库本身能保证数据的完整性,不需要应用程序的空值,而文件系统一般需要在程序端进行控制.

数据完整性有一下三种形式:

  1. 实体完整性保证表中有一个主键
  2. 域完整性保证每列数据的值满足特定的条件,实现:
    1. 选择合适的数据类型
    2. 外键约束
    3. 触发器
    4. default约束(默认值)
  3. 参照完整性保证两张表之间的关系(外键,触发器)

(2). 约束的创建和查找

约束的创建可以使用一下两种方式:

  1. 建立表时进行约束的定义
  2. 利用alter table命令创建约束

对于Unique Key(唯一索引)还能通过create unique index命令创建.

create table 库名.表名(
    字段名1 类型[(宽度) 约束条件],
    字段名2 类型[(宽度) 约束条件],
    字段名3 类型[(宽度) 约束条件]
);

// 常见约束
primary key (PK)      #标识该字段为该表的主键,可以唯一的标识记录,主键就是不为空且唯一当然其还有加速查询的作用
foreign key (FK)      #标识该字段为该表的外键,用来建立表与表的关联关系
not null              #标识该字段不能为空
unique key (UK)       #标识该字段的值是唯一的
auto_increment        #标识该字段的值自动增长(整数类型,而且为主键)
default               #为该字段设置默认值

unsigned              #将整型设置为无符号即正数
zerofill              #不够使用0进行填充

(3). 约束和索引的区别

​  当用户创建了一个唯一索引就创建了一个唯一的约束.

​  约束是一个逻辑的概念,用来保护数据的完整性,而索引是一个数据结构,既有逻辑上的概念,在数据库中还代表着物理存储的方式.

(4). 对错误数据的约束

​  MySQL数据库允许非法的或者不正确的数据插入或更新,又或者可以在数据库内部将其转化为一个合法的值,数据库本身没有对数据的正确性进行约束.

(5). ENUM和SET约束

​  MySQL数据库不支持传统的CHECK约束,但是通过ENUM(枚举类型,单选)和SET(集合类型,多选,求和)类型可以解决部分这样的约束要求.但对于连续值的万为约束或更复杂的约束,需要使用触发器来实现.

(6). 触发器与约束

​  触发器的作用是在执行insert,delete或者update命令之前或者之后自动调用SQL命令或存储过程.

​  创建触发器的命令如下,只有Super权限的MySQL用户才可以执行这条命令:

create trigger 触发器名 before|after 触发事件
on 表名 for each row
begin
	执行语句
end;

​  最多可以为一张表建立6个触发器,即inser,delete和update三种操作各一个before和after触发器.

​  MySQL只支持for each row的触发器,即按每行记录进行出发.

(7). 外键约束

​  外键用来保证参照完整性,InnoDB存储引擎完整支持外键约束.

​  一般来说,被引用的表被称为父表,引用表称为子表.外键定义时的on delete和on update表示在对父表进行delete和update操作时,对子表所进行的操作.

foreign key 
子表名(子表字段) references 父表名(父表字段)
[on delete restrict|cascade|set null|no action]
[on update restrict|cascade|set null|no action]
  • cascade:对子表进行同步
  • set null:设置子表为null(子表中的字段不能NOT NULL)
  • no action:不允许父表的此操作,抛出异常
  • restrict:同no action

​  MySQL中no action和restrict是一样的

​  InnoDB存储引擎会在外键建立的同时自动为外键列加上一个索引,可以很好的避免死锁问题.

7. 视图

​  MySQL数据库中,视图是一个命名的虚表,由一个SQL查询来定义,可以当做表使用,但没有物理存储.

(1). 视图的作用

create view 视图名 [视图列名]
as 查询语句
[with [cascaded|local] check option]

​  视图的主要用途之一就是被用作一个抽象装置,程序本身不需要关心基表的结构,只需要按照视图定义来取数据或者更新数据.同时起到一个安全层的作用.

​  用户对某些视图的更新操作,其本质就是通过的视图的定义来更新基本表.视图定义中的with check option就是针对于可更新视图的更新检查.加上该选项,MySQL数据库会对更新视图插入的数据进行检查,对于不满足**视图定义条件(也就是查询语句中的条件查询)**的插入,会抛出一个异常.不允许数据更新.

(2). 物化视图

​  物化视图是指该视图不是基于表的虚表,而是根据基表实际存在的实体表.可用于预先计算并保存多表的链接,聚集等耗时的SQL操作结果.

物化视图的刷新模式:

  • on demand:需要时刷新
  • on commit:实时刷新

刷新的方法:

  • fast:局部刷新
  • complete:全局刷新
  • force:通过判断选择前两种
  • never:不进行刷新

​  MySQL数据库不支持物化视图,不过可以使用其他方式实现.on demand的物化视图可以通过定时把数据转入另一张表来完成,其中不需要定义语法上的视图.如果要实现on commit的物化视图,需要使用触发器.

8. 分区表

(1). 概述

​  分区功能并不是在存储引擎层完成的,常见的存储引擎都支持,但不是所有.

​  分区的过程是将一个表或者索引分解为多个更小,更可管理的部分.将访问数据库的应用而言,从逻辑上讲,只有一个表或者索引.但是在物理上这个表或者索引可能由数十个物理分区组成.每一个分区都是独立的对象,可以独自处理,也可所为一个更大的对象的一部分进行处理.

​  MySQL支持的分区类型为水平分区(将不同行的数据分到不同的物理文件中),而不支持垂直分区(同之前,不同列).此外,MySQL分区是局部分区索引(一个分区中既存放了数据,有存放了索引),另一种是全局分区(数据存放在各个分区中,所有数据的索引放在一个对象中).

​  分区主要用于数据库高可用性的管理.

当前MySQL数据库支持一下几种类型的分区:

  • RANGE分区:行数据在一个连续的给定区间的数据放入一个分区.
  • LIST分区:面向离散的值
  • HASH分区:根据自定义的表达式的返回值进行分区
  • KEY分区:根据MySQL数据库提供的哈希函数来进行分区

​  不论建立何种类型的分区,如果表中存在主键或者唯一索引,那么分区别必须是唯一索引的一个组成部分.

​  唯一索引可以是允许NULL值的,并且分区列只要是唯一索引的一个部分就可以了(多个唯一索引之一).

(2). 分区类型

1). RANGE分区

​ RANGE分区,是最常用的一种分区类型.

create table t(
	value int
)engine=InnoDB
partition by RANGE(value)(
	partition p0 values less than (10),
    partition p1 values less than (20),
    partition p3 values less than maxvalue
);

​  这里范围是[10,20)插入p1,右边为开区间.

​  当插入一个不在分区中定义的值是,MySQL数据库会抛出异常,我们可以通过添加一个maxvalue值作为无限大来解决这个问题.

​  RANGE主要用于日期列的分区.如下所示:

create table t_date(
	value datetime
)engine=InnoDB
partition by RANGE(year(value))(
	partition p2008 values less than (2009),
    partition p2009 values less than (2010),
    partition pfuture values less than maxvalue
);

​  要删除响应时间的记录只需要删除分区即可(删除分区约束):

alter table 表名 drop partition 分区名;

​  其次,在进行查询语句时,SQL优化器会对查询范围进行裁剪,只搜索部分分区,所以可以大幅度优化查询速度.这被称为Partition Pruning(分区修减).对于RANGE分区的查询,优化器只能对YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()这类函数进行优化选择.

注意:
    where value>='2008-1-1' and value<='2008-12-31';
和
    where value>='2008-1-1' and value<'2009-1-1';
的优化是不同的,后者会搜索两个分区p2008和p2009
所以应当根据分区对SQL进行优化.

2). LIST分区

​  与RANGE分区类似,只是分区列的值是离散的.

create table t(
	value int
)engine=InnoDB
partition by RANGE(value)(
	partition p0 values in (1,3,5,7,9),
    partition p1 values in (0,2,4,6,8)
);

​  如果插入值不在分区的定义中,MySQL数据库同样会抛出异常.

​  在用insert插入多个行数据的过程中遇到分区未定义的值时,InnoDB存储引擎会撤销所有插入的操作,其他存储引擎有不同的操作.

3). HASH分区

​  HASH分区的目的是将数据均匀的分布到预先定义的各个分区中,保证个分区的数据数量大致是一样的.在RANGE和LIST分区中,必须明确制定一个给定的列支或者列值集合应该保存在那个分区中,但在HASH分区中,MySQL自动的完成这些操作.

​  需要使用partitions制定分区的数量.否则默认为1.

create table t(
	value int
)engine=InnoDB
partition by HASH(value)
partitions 4;

 还支持一种LINEAR HASH的分区(线性HASH).哈希函数的步骤如下:

  1. 给分区数量向上取整为2的幂值,记为v
  2. N = F( num ) & ( v-1 )
  3. 如果N>=分区数量,则在进行如下操作:
    1. v = CEIL( v/2 ) 除2,取整
    2. N = N & ( v-1 ) 二次进行哈希

​  LINEAR HASH分区的优点在于,增加,删除,合并和拆分分区将变得更加快捷.缺点在于各个分区间的数据分布可能不如HASH分区均衡.

4). KEY分区

​  KEY分区使用MySQL数据库提供的函数进行分区.

create table t(
	value int
)engine=InnoDB
partition by KEY(value)
partitions 4;

5). COLUMNS分区

​  前面介绍的分区都有局限性,分区的依据必须为整数,否则需要通过函数来转换.

​  MySQL 5.5版本开始支持COLUMNS分区,可视为RANGE分区和LIST分区的进化,可以直接使用非整型的数据(日期,字符,不支持float)进行分区.

​  对LIST分区的加强主要指对字符串进行分类.

​  在RANGE或者LIST后加上COLUMNS即可去掉转化函数.

create table t_date(
	value datetime
)engine=InnoDB
partition by RANGE COLUMNS (value)(
	partition p2008 values less than (2009),
    partition p2009 values less than (2010),
    partition pfuture values less than maxvalue
);

(3). 子分区

​  子分区是在分区的基础上在进行分区,MySQL数据库允许在RANGE和LIST分区上在进行一次HASH或KEY分区.语法如下:

create table t(
	value int
)engine=InnoDB
partition by RANGE(value)
subpartition by HASH(value)(
	partition p0 values less than (10)(
    	subpartition s0,
        subpartition s0
    ),
    partition p1 values less than (20)(
    	subpartition s2,
        subpartition s3
    ),
    partition p3 values less than maxvalue(
    	subpartition s4,
        subpartition s5
    )
);

注意事项:

  • 每个分区的子分区数量必须一致
  • 只要一个分区定义了子分区,那么所有分区都要有子分区
  • 每个子分区必须有名字,且唯一

(4). 分区中的NULL值

​  MySQL数据库的分区视NULL为无穷小的值.例如RANGE分区会将NULL值插入最左侧最小的分区.但在LIST分区中必须明确指出那个分区可以放置NULL值.HASH和KEY分区中,NULL的哈希结果总是为0.

(5). 分区和性能

​ 数据库应用分为两类

  • OLTP(在线事务处理):一般指高并发情况下的数据库设计,如Blog、电子商务、网络游戏等
  • OLAP(在线分析处理):指多样化查询的数据库设计,如数据仓库、数据集市

 对于OLAP的应用,分区可以很好的提高效率,但对于OLTP的应用,分区很可能导致增加IO操作,而非提高效率.

(6). 在表和分区之间交换数据

​  MySQL 5.6开始支持分区或者子分区中的数据与另一个非分区表中的数据进行交换.

alter table 分区表名 exchange partition 分区表中的分区名 with table 非分区表

在表和分区间交换数据,必须满足下面的条件:

  • 要交换的表需和分区表有着相同的表结构,但是表不能含有分区
  • 在非分区表中的数据必须在交换的分区定义内
  • 被交换的表不能包含有外键,或有其他的表含有对该表的外键作用
  • 用户除了需要ALTER、INSERT、CREATE权限外,还需要DROP的权限

两个注意事项:

  • 交换表,不会触发交换表和被交换表上的触发器
  • AUTO_INCREMENT column is reset
Published 141 original articles · won praise 47 · views 40000 +

Guess you like

Origin blog.csdn.net/qq_41596568/article/details/104332413