InnoDB是当前MySQL的默认的存储引擎,也是互联网等公司数据库存储引擎的不二选择。InnoDB的特性如下:
- 支持数据库事务。在可重复读的隔离级别下,解决了不可重复读的问题。并且通过间隙锁的引入解决了幻读的问题。
- 支持行级锁和表级锁。默认是行级锁,因此具备更高的并发度。
- 支持外键。
- 为处理巨大数据量时的最佳性能而设计。CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。
- InnoDB中不保存表的行数。清空整个表时,InnoDB是一行一行的删除,因此效率非常慢。
- InnoDB使用B+树来存储索引,因此具有查询效率高的特点。并且支持索引上的范围查询。
InnoDB存储引擎主要由三部分组成,分别是:存储结构、内存结构和线程结构。视频讲解如下:
一、存储结构
InnoDB的存储结构又可以分为逻辑存储结构和物理存储结构。下面分别进行介绍。
(一)逻辑存储结构
InnoDB存储引擎的逻辑存储结构和Oracle大致相同,所有数据都被逻辑地存放在一个空间中,我们称之为表空间(tablespace)。表空间又由段(segment)、区(extent)、页(page)组成。InnoDB存储引擎的逻辑存储结构大致如下图所示。
- 表空间
表空间可以看做是InnoDB存储引擎逻辑结构的最高层,所有的数据都是存放在表空间中。默认情况下InnoDB存储引擎有一个共享表空间ibdata1,用于存放撤销(Undo)信息、系统事务信息、二次写缓冲(double write buffer)数据等。
- 段
表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等。InnoDB存储引擎表是索引组织的(Index Organized).因此数据即索引,索引即数据。与Oracle不同的是,InnoDB存储引擎对于段的管理是由引擎本身完成,这和Oracle的自动段空间管理(ASSM)类似,没有手动段空间管理(MSSM)的方式,这从一定程度上简化了DBA的管理。
- 区
区是由连续的页组成,是物理上连续分配的一段空间,每个区的大小固定是1MB。对于大的数据段,InnoDB存储引擎最多每次可以申请4个区,以此来保证数据的顺序性能。
- 页
InnoDB的最小物理存储分配单位是页,页的默认大小是16Kb,可以通过下面的方式查看。
mysql> show variables like 'innodb_page_size'; # 输出的信息如下: +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_page_size | 16384 | +------------------+-------+
(二)物理存储结构
MySQL与Oracle一样都是通过逻辑存储结构来管理物理存储结构,即管理硬盘上存储的各种文件。下面将详细介绍InnoDB存储引擎中的主要文件。
- 数据文件
“.ibd”文件和ibdata文件 这两种文件都是存放Innodb数据的文件,之所以有两种文件来存放Innodb的数据(包括索引),是因为 Innodb 的数据存储方式能够通过配置来决定是使用共享表空间存放存储数据,还是独享表空间存放存储数据。
- 重做日志文件(redo log)
redo log是InnoDB存储引擎层生成的日志,主要为了保证数据的可靠性和事务的持久性。每个redo log默认的大小是1G,由参数“innodb_log_file_size”参数决定。
mysql> show variables like "innodb_log_file_size"; # 输出的信息如下: +----------------------+------------+ | Variable_name | Value | +----------------------+------------+ | innodb_log_file_size | 1073741824 | +----------------------+------------+
- 撤销日志文件(undo log)
undo log中记录的是旧版本的数据,当我们对记录做了变更操作时就会产生undo记录。当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录。
从MySQL8.0版本开始,MySQL默认对undo进行了分离操作。也就是说,不需要在初始化中手动配置参数,默认会在MySQL数据目录下生成两个10兆大小的undo表空间文件“undo_001” 和 “undo002” 并且可以在线的增加和删除undo表空间文件进行动态扩容和收缩。
- 参数文件
在MySQL实例启动时,数据库会先去读一个配置参数文件,用来寻找数据库的各种文件所在位置以及指定某些初始化参数。在默认情况下,MySQL实例会按照一定的顺序在指定的位置进行读取,通过下面的语句可以查看读取参数文件的顺序。
mysql --help | grep my.cnf # 输出的信息如下: /etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf
- 错误日志
类似Oracle的告警日志,MySQL的错误日志文件对MySQL的启动、运行、关闭过程中出现的问题进行了记录。执行下面的语句查看MySQL的错误日志:
mysql> show variables like 'log_error'; # 输出的信息如下: +---------------+---------------------------------+ | Variable_name | Value | +---------------+---------------------------------+ | log_error | /usr/local/mysql/data/error.log | +---------------+---------------------------------+
- 二进制日志文件binlog
binlog文件记录了对MySQL数据库执行更改的所有操作,但是不包括SELECT和SHOW这类操作,因为这类操作对数据本身并没有修改。若操作本身并没有导致数据库发生变化,那么该操作也会写入二进制日志。
- 慢查询日志
慢查询日志可以把超过参数long_query_time时间的所有SQL语句记录进来,帮助DBA人员优化所有有问题的SQL语句。通过mysqldumpslow工具可以查看慢查询日志。
- 全量日志
全量日志(general log)会记录MySQL数据库所有操作的SQL语句,包含select和show。默认情况下,禁用常规查询日志。
二、内存结构
实际上MySQL内存的组成和Oracle类似,也可以分为SGA(系统全局区)和PGA(程序缓存区)。通过下面语句可以进行查看。
mysql> show variables like '%buffer%';
三、线程结构
InnoDB的线程结构主要分为主线程结构、I/O线程结构和其他线程结构。
(一)主线程结构
后台线程中的主线程(master thread),优先级别最高。主线程内部有四个循环:主循环(loop)、后台循环(backgroud loop)、刷新循环(flush loop)和暂定循环(suspend loop)。其中最主要的就是主循环(loop),该循环分为每1秒操作和每10秒操作两种情况。
(二)I/O线程结构
MySQL有4大如下I/O线程,分别是:
- read thread:数据库的读请求线程,默认值是4个。
- write thread:数据库的写请求线程,默认值是4个。
- redo log thread:负责把日志缓存中的内容刷新到redo log文件中。
- change buffer thread:负责把插入缓存(change buffer)中的数据刷新写到磁盘的数据文件中。
(三)其他线程结构
线程结构包括:
- page clean thread:将脏数据写入到磁盘,脏数据写盘后相应的redo就可以覆盖,然后达到redo循环使用的目的。
- purge thread:负责删除无用的undo页。
- error monitor thread:负责数据库报错的线程。
- lock monitor thread:负责监控锁的线程。