前言:本文是自己阅读《Mysql技术内幕——InnoDB存储引擎》一书的感悟笔记,主要是为了将阅读和实践相结合起来,文中会穿插自己的理解及工作中的实践心得。
1、什么是InnoDB
InnoDB,是MySQL的数据库引擎之一,现为MySQL的默认存储引擎(MySQL5.1版本之前默认引擎是MyISAM),Innodb引擎提供了对数据库ACID事务的支持,同时还提供了行级锁和外键的约束。MySQL运行的时候,Innodb会在内存中建立缓冲池,用于缓冲数据和索引。
该引擎的优点:
a、当需要使用数据库的事务时,该引擎是首选。由于锁的粒度小,是行级锁,INSERT或UPDATE等写操作是不会锁定全表的。所以在并发度较高的场景下使用会提升性能和效率的。
b、支持外键(foreign key)
c、如果数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB
该引擎的缺点:
a、是不支持全文搜索(FULLTEXT类型)的;
b、执行速度比较慢(主要是和MyISAM比较);
c、不会保存表的行数,当执行 select count(*) from tablename 指令的时候,需要进行扫描全表;
1、InnoDB使用什么类型的索引
InnoDB是聚集索引,使用B+Tree作为索引结构,聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。如果使用非主键索引,那就需要经过两次查询,先查询辅助索引找到主键,然后再通过主键查询到数据。
如果没有设定主键或者非空唯一索引,InnoDB会选区一个 not null unique key 作为主键,如果还是没有,就会自动生成一个6字节的主键(用户不可见),主键是索引到数据页,不是索引到具体的行位置。
自定义的主键不宜过大,因为主键太大,一是影响查找效率,二是其他辅助索引也都会很大。
2、InnoDB支持事务吗
InnoDB提供事务支持、外键(foreign key)等高级数据库功能。
3、对AUTO_INCREMENT的操作
InnoDB如果指定了AUTO_INCREMENT列,那该列必须是索引。如果该索引是组合索引,那也必须是组合索引的第一列。在数据词典里的InnoDB表句柄会包含一个名为自动增长计数器的计数器,它被用在为该列赋新值。自动增长计数器仅被存储在主内存中,而不是存在磁盘上。
4、表的行数
InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍全表来计算有多少行。为什么不像MyISAM那样保存行数到索引中呢?因为innodb保存行数的成本太高。
5、操作数据时的锁
提供行锁(locking on row level),提供不加锁读取(non-locking read in SELECTs),另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表, 例如update table set num=1 where name like "%xxx%"。
6、数据存储
Innodb存储引擎存储数据库数据,一共有两个文件(没有专门保存数据的文件):
a、frm文件:与表相关的元数据信息都存放在frm文件,包括表结构的定义信息等。
b、ibd文件或.ibdata文件:数据和索引存储文件。这两种文件都是存放innodb数据的文件,之所以用两种文件来存放innodb的数据,是因为innodb的数据存储方式能够通过配置来决定是使用共享表空间存放存储数据,还是用独享表空间存放存储数据。独享表空间存储方式使用.ibd文件,并且每个表一个ibd文件,共享表空间存储方式使用.ibdata文件,所有表共同使用一个ibdata文件,使用哪种方式的参数在mysql的配置文件中 innodb_file_per_table。
表空间(ibd文件),一个MySQL实例可以对应多个表空间,用于存储记录,索引等数据。
段,分为数据段、索引段、回滚段,innodb是索引组织表,数据段就是B+Tree的叶子节点,索引段为非叶子节点,段用来管理多个区。
区,表空间的单元结构,每个区的大小为1M,默认情况下,innodb存储引擎页大小为16K,即一个区中一共有64个连续的页。
页,是innodb存储引擎磁盘管理的最小单元,每个页的大小为16K,为了保证页的连续性,innodb存储引擎每次从磁盘申请4~5个区。
行,innodb存储引擎数据是按行进行存储的。Trx_id 最后一次事务操作的id、roll_pointer滚动指针。
7、如何更新数据
innodb更新数据和它的内存结构有关,内存结构由Buffer Pool、Change Buffer和Log Buffer组成。
Buffer Pool: 缓冲池是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池么有数据,则从磁盘加载并缓存),然后再以一定频率刷新磁盘,从而减少磁盘IO,加快处理速度。
缓冲池以page页为单位,底层采用链表数据结构管理page,根据状态,将page分为三种类型:
1、free page 即空闲page,未被使用。
2、clean page 被使用page,数据没有被修改过。
3、dirty page 脏页,被使用page,数据被修改过,这个page当中的数据和磁盘当中的数据 不一致。说得简单点就是缓冲池中的数据改了,磁盘中的没改,因为还没有落盘。
Change Buffer :更改缓冲区(针对于非唯一二级索引页),在执行DML语句时,如果这些数据page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区Change Buffer中,在未来数据被读取时。再将数据合并到Buffer Pool中,再将合并后的数据刷新到磁盘中。
二级索引通常是非唯一的,并且以相对随机的顺序插入二级索引页,同样,删除和更新可能会影响索引树中不相邻的二级索引页。如果每一次都操作磁盘,会造成大量磁盘IO,有了Change Buffer之后,我们可以在缓冲池中进行合并处理,减少磁盘IO。
Adaptive Hash Index: 自适应hash索引,用于优化对Buffer Pool数据的查询,InnoDB存储引擎会监控对表上各索引页的查询,如果观察到hash索引可以提升速度,则建立hash索引,称之为自适应hash索引。无需人工干预,系统根据情况自动完成。
参数:innodb_adaptive_hash_index
Log Buffer: 日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log、undo log),默认大小为16M,日志缓冲区的日志会定期刷新到磁盘中,如果需要更新,插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘IO。
参数: innodb_log_buffer_size 缓冲区大小
innodb_flush_log_at_trx_commit 日志刷新到磁盘时机
innodb_flush_log_at_trx_commit=1 表示日志在每次事务提交时写入并刷新到磁盘
2 表示日志在每次事务提交后写入,并每秒刷新到磁盘一次
0 表示每秒将日志写入并刷新到磁盘一次。
独立表空间(*.ibd): 每个表的文件表空间包含单个innodb表的数据和索引,并存储在文件系 统上的单个数据文件中。 参数: innodb_file_per_table
通用表空间: 需要通过create tablespace 语法创建,创建表时 可以指定该表空间。
create tablespace xxx add datafile 'file_name' engine=engine_name
create table table_name .... tablespace xxx
撤销表空间(undo tablespaces): MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16K,undo_001,undo_002),用于存储undo log 日志
临时表空间(Temporary Tablespaces): innodb使用会话临时表空和全局表空间,存储用 户创建的临时表等数据。
双写缓冲区(Doublewrite Buffer files): innodb引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入缓冲区文件中,便于系统异常时恢复数据。
重做日志(Redo Log): 是用来实现事务的持久性,该日志文件由两部分组成,重做日志缓冲区(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中,当事务提交之后会把修改信息都会存储到该日志中,用于在刷新脏页到磁盘时,发送错误时,进行数据恢复使用。以循环方式写入重做日志文件,涉及两个文件ib_logfile0,ib_logfile1。
8、InnoDB行存储
行记录的存储格式有两种,Barracuda和Antelope。
Barracuda:主要有compressed,dynamic等行格式
Antelope:主要有compact,redundant等行格式
由 innodb_file_format 参数决定,目前可选值有Antelope和Barracuda,默认为前者。
由于共享表空间默认为Antelope,因此要想使用Barracuda为默认值,还必须先设置innodb_file_per_table=1;