InnoDB引擎中的表

时间:2022-09-24 10:21:03

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)组成。
InnoDB引擎中的表
(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引擎中的表
如果想详细了解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表的四种分区类型