本文主要是针对《Mysql技术内幕:InnoDB 存储引擎》一书中第四章关于表相关概念的概括和总结,主要包括组织索引表,InnoDB 逻辑存储结构,InnoDB 行记录格式,InnoDB 数据页结构,表相关的约束问题,视图,表分区。
索引组织表是指按照主键的顺序组织存放数据的表,InnoDB 存储引擎创建的表都是索引组织表。InnoDB 主键定义规则如下:
InnoDB 所有数据都存放在一个空间中,称之为表空间,表空间由段,区,页组成。
innodb_file_per_table 参数:
表空间由各个段组成,主要分为索引段,数据段以及回滚段。其中数据段存放在 B+ 树的叶子节点,索引段存放在 B+ 树的非叶子节点。
区由连续的页组成:
InnoDB 存储引擎中,常见的页的类型有:
InnoDB 存储引擎中,数据是按照行进行存放的,最多可以存放 7992 条行记录
InnoDB 中行记录格式通过在建表语句中关键字 ROW_FORMAT=xxx 来指定。
create Table mytest (
t1 varchar(10),
t2 varchar(10)
) engine=INNODB ROW_FORMAT=COMPACT
在 InnoDB 1.0.x 版本之前,提供了 Compact 和 Redundant 两种格式来存放行记录数据。
在 InnoDB 1.0.x 版本之后,引入了新的两种行记录格式:Compressed 和 Dynamic。
存放顺序:
不管是 CHAR 类型还是 VARCHAR 类型,NULL 在 Compact 存储格式下都不占用存储空间。
存放顺序:
对于 VARCHAR 类型的 NULL 值同样不占用存储空间,但是 CHAR 类型的 NULL 值会占用存储空间。
InnoDB 数据页由以下七个部分组成:
File Header 用来记录页的一些头信息,共占用 38 个字节,主要存放关于当前页的一些信息,包括下面一些信息:
Page Header 用来记录数据页的状态信息,主要包括下面一些信息:
Infimun 和 Supremum Records 是两个虚拟的行记录,用来存放记录的边界, Infimun 记录比所有主键值都要小的记录,Supremum Records 记录比所有主键值都要大的值,这两个值在页创建时被创建,任何情况下都不会删除。
User Records 存放行记录数据,Free Space 指的是空闲空间,当一条记录被删除时就加入到空闲链表结构里
Page Directory 存放了记录的相对位置,称为槽,并不是每行记录一个槽,是一个稀疏目录,一个槽里面可能有多个记录,按照主键值顺序索引存放。
Page Directory 主要用于在页中根据索引查询某条记录时,通过二分查找法查到一个粗略的位置,最后在通过行记录中的 next_record 来继续查找相关记录。
所以整个数据查询的逻辑如下:
- 通过 B+ 树找到该记录所在的页,数据库把该页载入内存
- 然后再根据 Page Directory 的二分查找法找到一个粗略的记录位置
- 最后再根据行记录中的 next_record 来继续查找相关记录
File Trailer 为了检查页是否被完整的写入磁盘或者是否完整从磁盘读取,可以通过以下两个参数对其进行控制:
数据的完整性包括下面三个部分:
CREATE TABLE `dage` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(32) default '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `xiaodi` (
`id` int(11) NOT NULL auto_increment,
`dage_id` int(11) default NULL,
`name` varchar(32) default '',
PRIMARY KEY (`id`),
KEY `dage_id` (`dage_id`),
CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
- SET NULL:表示外键发生变化时,子表相应字段被设置为 NULL
- NO ACTION:表示外键发生变化时,抛出错误,不允许该类操作
- SET DEFAULT:表示外键发生变化时,设置成相应的默认值
- RESTRICT:表示父表发生变化时,抛出错误,不允许该类操作,和 NO ACTION 类似
默认情况下,如果向 mysql 中插入不符合约束规范的数据,mysql 会给予警告提示,并且将不符合规范的数据自动转换为符合符合规范的数据,并不会报错。
可以通过参数 sql_mode = “STRICT_TRANS_TABLES” 强制对输入值进行合法性检查,如果不满足条件则报错。
create view v_match
as
select a.PLAYERNO,a.NAME,MATCHNO,WON,LOST,c.TEAMNO,c.DIVISION
from
PLAYERS a,MATCHES b,TEAMS c
where a.PLAYERNO=b.PLAYERNO and b.TEAMNO=c.TEAMNO;
区分特性:
分区优点:
分区分类:
create table t(
id int
) ENGINE=INNODB
PARTITION BY RANGE (id)(
PARTITION p0 values less then (10),
PARTITION p1 values less then (20),
PARTITION p1 values less then MAXVALUE - MAXVALUE 表示正无穷
)
create table t(
id int
) ENGINE=INNODB
PARTITION BY RANGE (id)(
PARTITION p0 values in (10, 20),
PARTITION p1 values in (30, 40, 50)
)
create table t(
id int,
b DATETIME
) ENGINE=INNODB
PARTITION BY HASH (YEAR(b))
PARTITIONS 4; - 表示设置4个分区
create table t(
id int,
b DATETIME
) ENGINE=INNODB
PARTITION BY KEY (b)
PARTITIONS 4; - 表示设置4个分区
create table rcx (
a int,
b int,
c char(3),
d int
) engine=innoDB
partition by range columns(a,d,c)(
partition p0 values less than (5, 10, 'ggg'),
partition p1 values less than (10, 20, 'mmm'),
partition p3 values less than (maxvalue, maxvalue, maxvalue),
)
子分区:
-- 不定义每个子分区
CREATE TABLE tb_sub (id INT, purchased DATE)
PARTITION BY RANGE( YEAR(purchased) )
SUBPARTITION BY HASH( TO_DAYS(purchased) )
SUBPARTITIONS 2 (
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN MAXVALUE
);
-- 定义每个子分区
CREATE TABLE tb_sub_ev (id INT, purchased DATE)
PARTITION BY RANGE( YEAR(purchased) )
SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
PARTITION p0 VALUES LESS THAN (1990) (
SUBPARTITION s0,
SUBPARTITION s1
),
PARTITION p1 VALUES LESS THAN (2000) (
SUBPARTITION s2,
SUBPARTITION s3
),
PARTITION p2 VALUES LESS THAN MAXVALUE (
SUBPARTITION s4,
SUBPARTITION s5
)
);
分区中 NULL 值处理:
分区与性能:
并不是所有启动了分区的表,数据库查询就会变快。一般对于 OLTP(在线事务处理) 的应用不建议使用分区,建议对于 OLAP(在线分析处理)使用分区。一般 OLTP 表数据量不是特别大,而且大部分查询会根据索引查询,采用分区反而会增加 IO 的读写次数使性能下降。
表和分区交换数据:
通过 ALTER TABLE … EXCHANGE PARTITION 语法可以将某个分区的数据和另外一个非分区表中的数据进行交换,必须满足以下条件:
alter table e exchange partition p0 with table e2;