1.InnoDB存储引擎表的类型
在InnoDB中,表是根据主键的顺序组织存放的,这种存储方式的表称为索引组织表。在InnoDB引擎表中,每张表都有个主键(Primary Key),如果在创建表时,没有显式地指定主键,则InnoDB存储引擎会按如下方式选择或创建主键:
(1)首先判断表中是否有非空的唯一索引,如果有,则改列即为主键;
(2)如果不符合上述条件,InnoDB存储引擎会自动创建一个6字节大小的指针。
当表中有多个非空的时,InnoDB存储引擎将选择建表时第一个定义的非空唯一索引为主键。需要注意的时,主键的选择是根据定义索引的顺序而不是建表时列的顺序。
如:create table tb1( a int not null, b int null, c int not null, d int not null, unique key(b), unique key(d), unique key(c) ); 根据判断条件,列d为表tb1的主键。
2.InnoDB存储引擎的存储结构
2.1InnoDB存储引擎的逻辑存储结构
InnoDB存储引擎中,所有的数据都被逻辑地存放在一个空间中,我们称之为表空间(tablespace)。表空间又由段(segment)、区(extent)、页(page)组成。
(1)表空间
表空间可以看做是InnoDB存储引擎逻辑结构的最高层,所有的数据都是存放在表空间中。 默认情况下InnoDB存储引擎有一个共享表空间ibdata1,即所有数据都放在这个表空间内。如果我们启用了参数innodb_file_per_table,则每张表内的数据可以单独放到一个表空间内。 对于启用了innodb_file_per_table的参数选项,需要注意的是,每张表的表空间内存放的只是数据、索引和插入缓冲,如撤销(Undo)信息,系统事务信息,二次写缓冲等还是存放在共享表空间中。
(2)段
表空间是由各个段组成的,常见的段有数据段,索引段回滚段等。数据段即为B+树的页节点,索引段即为B+树的非页节点。 注:并不是每个对象都有段,更准确地说,表空间是由分散的页和段组成。
(3)区
区是由64个连续的页组成,每个页大小为16KB,即每个区大小为1MB。对于大的数据段,InnoDB存储引擎最多每次可以申请4个区,以此来保证数据的顺序性能。 注:在每个段开始时,现有32个页大小的碎片页来存储数据吗,当这些页用完之后才是64个连续页的申请。
(4)页
页是InnoDB存储引擎磁盘管理的最小单位。常见的页类型有: ①数据页 ②Undo页 ③系统页 ④事务数据页 ⑤插入缓冲位图页 ⑥插入缓冲空闲列表页 ⑦未压缩的二进制大对象页 ⑧压缩的二进制大对象页
(5)行
InnoDB存储引擎是面向行的,也就是说数据的存放是按行进行存放。每个页存放的行记录也是有硬性定义的,最多允许存放16KB/2-200行的记录,即7992行记录。
2.2InnoDB存储引擎的物理存储结构
从物理角度看,InnoDB存储引擎表由共享表空间、日志文件组(更准确地说是Redo文件组)、表结构定义文件组成。若果将innodb_file_per_table设置为on,则每个表将独立地产生一个表空间文件,以ibd结尾,数据、索引、表的内部数据字典信息都将保存在这个单独的表空间文件中。表结构定义文件以frm结尾,这个与存储引擎无关,任何存储引擎的表结构定义文件都一样,为.frm文件。
3.InnoDB行记录格式
InnoDB存储引擎有两类行记录格式
(1)Antelope文件格式
①Compact ②Redundant(2)Barracuda文件格式
①Compressed ②Dynamic
参数innodb_file_format用来指定文件格式,innodb_file_format_check用来检测InnoDB存储引擎文件格式的支持度,该值默认为on。
如果想详细了解这些行记录格式可阅读此博客:InnoDB的行记录格式, Compact, Redundant, Compressed, Dynamic
4.InnoDB数据页结构
页是InnoDB存储引擎管理数据库的最小磁盘单位。页类型为B-tree node的页即是表中行的实际数据。
InnoDB数据页由以下七个部分组成,如图所示:
File Header(文件头)。 Page Header(页头)。 Infimun+Supremum Records。 User Records(用户记录,即行记录)。 Free Space(空闲空间)。 Page Directory(页目录)。 File Trailer(文件结尾信息)
如果想详细了解InnoDB数据页结构可阅读此博客:这里写链接内容
5.InnoDB表的约束
5.1数据完整性
1.数据完整性有三种形式:
(1)实体完整性:保证表中有一个主键。在InnoDB存储引擎表中,可以通过定义Primary Key或者Unique Key约束来保证实体的完整性。或者可以通过编写一个触发器来保证数据完整性。 (2)域完整性:保证数据的值满足特定的条件。在InnoDB存储引擎表中,域完整性可以铜鼓一下几种途径来保证:选择合适的数据类型可以确保一个数据值满足特定条件,外键(Foreign Key)约束,编写触发器,还可以考用DEFAULT约束作为强制域完整性的一个方面。 (3)参照完整性:保证两张表之间的关系。InnoDB存储引擎支持外键,因此允许用户定义外键以强制参照完整性,也可以通过编写触发器以强制执行。
2.对于InnoDB存储引擎而言,提供了四种约束:
(1)primary key 或 unique key (2)foreign key (3)default (4)not null
5.2约束的创建
对于约束的创建,可以在建表的时候就进行定义,也可以在之后使用ALTER TABLE命令来进行创建。
下面是一个简单的创建表的语句,表上有一个主键和一个唯一键: create table u( id int, name varchar(20), id _card char(18), primary key(id),unique key(name) ); 查找约束: select constraint_name,constraint_type from information_schema.TABLE_CONSTRAINTS; 通过ALTER TABLE命令来进行创建,可以定义约束的名字: alter table u add unique key uk_id_card(id_card); 创建foreign key 需要两张表: create table p( id int, u_id int, primary key(id), foreign key(u_id) references p(id) );
1.对于错误数据的约束:
默认情况下,MySQL数据库允许非法或者不正确数据的插入或更新,或者内部将其转化为一个合法的值,如对于not null的字段插入一个null值,会将其更改为0再进行插入。
如: create table a( id int not null, date date not null ); insert into a select NULL,'2018-02-30'; 对数据库插入了一个NULL值和一个非法的时间值,MySQL没有报错,而是显示了警告。 如果我们想约束对于非法数据的插入或更新,MySQL是提示报错而不是警告,那么我们应该设置参数 sql_modle,同来严格审核输入的参数。 如:set sql_modle='STRICT_TRANS_TABLES'; insert into a select NULL,'2018-02-30'; 将会报错。
2.ENUM和SET约束
MySQL不支持传统的CHECK约束,但是通过ENUM和SET类型可以解决部分这样的约束需求。
如: create table a( id int, sex enum('male','female') ); insert into a select 1,'bi'; 插入上述数据不会报错,只会发出警告。因此如果想实现CHECK约束,还需要设置参数sql_modle。 如:set sql_modle='STRICT_TRANS_TABLES'; insert into a select 1,'bi'; 将会报错。
3.触发器与约束
创建触发器的命令是create trigger,只有具备Super权限的MySQL用户才可以执行这条语句: CREATE [DEFINER {user | CURRENT_USER}] TRIGGER trigger_name BEFORE|AFTER INSERT|UPDATE|DELETE ON table_name FOR EACH ROW trigger_stmt 假设有一个用户消费表,每次用户购买一样物品后其金额都是减的,如这时有不怀好意的人做了类似减去一个负值的操作,这种情况应该避免。 create table usercash( userid int, cash int unsigned not null); insert into usercash select 1,1000; update usercash set cash=cash-(-20) where id=1; 对于数据来说,上述的内容没有任何问题,不会报错。但是从逻辑上来说这时错误的,消费就该减去一个正值而不是负值。因此这时通过触发器;来约束这个逻辑行为的话,可以如下操作: create table usercash_err_log(//记录错误的表格 userid int not null, old_cash int unsigned not null, new_cash int unsigned not null, user varchar(30), time datetime ); //创建触发器 delimiter $$ create trigger tgr_usercash_update before update on usercash for each row begin if new.cash-old.cash>0 then insert into usercash_err_log select old.cash,new.cash,user(),now(); set new.cash=old.cash; end if; end; $$ //后续操作 delete from usercash; insert into usercash select 1,1000; update usercash set cash=cash-(-20) where id=1;4.外键 外键的定义:
[CONSTRAINT[symbol]] FOREIGN KEY [index_name] (index_col_name,...) REFERENCES table_name (index_col_name,..) [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION
我们可以在CREATE TABLE 时就添加外键,也可以在创建表之后通过ALTER TABLE命令来添加。
一个简单的外键创建例子: create table parent( id int not null primary key (id) ); create table child( id int, parent_id int, index par_id ( parent_id), foreign key ( parent_id) references parent(id) );
一般来说,我们称被引用的表为父表,另一个引用的表为子表。外键定义为ON DELETE,ON UPDATE表示父表做DELETE和UPDATE操作是子表所做的操作。可定义为:
(1)CASCADE:当父表发生DELETE或UPDATE操作时,相应的子表中的数据也被DELETE或UPDATE
(2)SET NULL:当父表发生DELETE或UPDATE操作时,相应子表中的数据被更新为NULL值。当然,子表中的相对应的列必须允许NULL值
(3)NO ACTION:当父表发生DELETE或UPDATE操作时,抛出错误,不允许这类操作发生。这是默认值。
(4)RESTRICT:当父表发生DELETE或UPDATE操作时,抛出错误,不允许这类操作发生。如果定义外键时没有指定ON DELETE或ON UPDATE,这就是默认的外键设置。
注:可以通过foreign_key_checks参数是否需要进行外键检查。该值默认为1,需要检查。可设置为0,不进行外键检查。
6.视图
视图是一个命名的虚表,它有一个查询来定义,可以当表使用。与表不同的是,视图中的数据没有物理表现形式。
创建视图的语法:
CREATE [OR REPLACE] [ALGORITHM={UNDEFINED | MERGE | TEMPTABLE}] [DEFINER={user | CURRENT_USER}] [SQL SECURITY { DEFINER | INVOKER }] VIEW view_name [(colimn_list)] AS select_statement [WITH [CASCADE | LOCAL ] CHECK OPTION]
关于视图可阅读此博客:
Mysql中的视图
7.分区表
MYSQL支持四种类型的分区:
(1)RANGE分区:行数据基于属于一个给定连续区域的列值放入分区。MySQL数据库5.5开始支持RANGE COLUMNS的分区。 (2)LIST分区:和RANGE分区类似,只是LIST分区面向的是离散的值。MYSQL数据库5.5开始支持LIST COLUMNS的分区。 (3)HASH分区:根据MySQL数据库提供的哈希函数进行分区。 (4)KEY分区:根据用户自定义的表达式的返回值进行分区,返回值不能为负数。
有关分区表的详细介绍可参考此博客:MySQL表的四种分区类型