,InnoDB 发展史
时间 | 事件 | 备注 |
---|---|---|
1995 | 由 Heikki Tuuri 创建 Innobase Oy 公司,开发 InnoDB 存储引擎 | Innobase 开始做的是数据库,希望卖掉该公司 |
1996 | MySQL 1.0 发布 | |
2000 | MySQL3.23 版本发布 | |
2001 | InnoDB 存储引擎集成到 MySQL 数据库 | 以插件方式集成 |
2006 | Innobase 被 Oracle 公司收购(InnoDB 作为开源产品,性能和功能很强大) | InnoDB 在被收购后的,MySQL 中的 InnoDB 版本没有改变 |
2010 | MySQL5.5 版本 InnoDB 存储引擎称为默认存储引擎 | MySQL 被 Sun 收购,Sun 被 Oracle 收购,使得 MySQL 和 InnoDB 重新在一起配合开发 |
至今 | 其他存储引擎已经不再得到 Oracle 官方的后续开发 |
,InnoDB 重要特性一览
- Fully ACID(InnoDB 默认的 Repeat Read 隔离级别就支持)
- Row-level Locking(支持行锁)
- Multi-version concurrency control(MVCC)(支持多版本并发控制)
- Foreign key support(支持外键)
- Automatic deadlock detection(死锁自动检测)
- High performance,High scalability,High availability(高性能, 高扩展, 高可用)
, 物理存储结构
3.1 主要组成部分
表空间文件:
独立表空间
共享表空间
undo 表空间(MySQL5.6 开始)
重做日志文件:
物理逻辑日志
没有 Oracle 的归档重做日志
3.2 细说表空间文件
表空间的概念:
表空间是一个逻辑存储的概念
表空间可以由多个文件组成
支持裸设备(可以直接使用 O_DIRECT 方式绕过缓存, 直接写入磁盘)
表空间的分类:
共享表空间(最早只有这个)
存储元数据信息
存储 Change Buffer 信息
存储 Undo 信息
MySQL4.0 之前所有数据都是存储在共享表空间中
独立表空间
MySQL4.0 开始, 支持每张表对应一个独立表空间(ibd 文件)
innodb-file-per-table=1(默认为 1, 这个参数关掉创建表, 会发现对应的库下面没有该表的 idb 文件)
分区表可以对应多个 ibd 文件
undo 表空间
MySQL5.6 版本支持独立的 Undo 表空间, 默认是 0, 即 undo 记录在共享表空间中
innodb_undo_tablespaces(该值 8.0 开始将会被剔除, 不可修改, 默认写死, 为 2)
临时表空间
MySQL5.7 增加了临时表空间(ibtmp1)
innodb_temp_data_file_path
3.3 看下数据目录
[root@VM_0_5_centos data3306]# ll ib*
-rw-r----- 1 mysql mysql 16285 Feb 4 18:15 ib_buffer_pool
-rw-r----- 1 mysql mysql 79691776 Feb 24 10:53 ibdata1 #共享表空间
-rw-r----- 1 mysql mysql 50331648 Feb 24 10:53 ib_logfile0 #重做日志
-rw-r----- 1 mysql mysql 50331648 Feb 4 15:06 ib_logfile1
-rw-r----- 1 mysql mysql 12582912 Feb 24 10:14 ibtmp1 #临时表空间
两个 ib_logfile 是循环交替写入的, SSD 下尽可能设大, 单个文件 4G/8G, 设置太小可能会导致脏页刷新时 hang 住
MySQL 中现在只有这两个文件不会归档, 最老的 3.23 版本支持归档, 因为 MySQL 有二进制日志所以把这个功能阉割了
- [root@VM_0_5_centos data3306]# cd test
- [root@VM_0_5_centos test]# ll
- total 228
-rw-r----- 1 mysql mysql 65 Feb 4 13:21 db.opt #记录默认字符集和字符集排序规则
-rw-r----- 1 mysql mysql 8554 Feb 1 15:45 abc.frm #表结构文件
-rw-r----- 1 mysql mysql 98304 Feb 24 10:53 abc.ibd #独立表空间
就性能而言, 独立和共享速度是一样的, 基本上区别
虽然 ibadta1 是一个文件, 但是在底层申请也是 1 兆 1 兆地申请的空间, 是连续的(两种都是以区的方式来管理), 在磁盘上的表现是一样的, 1M 的数据基本上可以认为是连续的
tips:
sysbench 去测 8 个文件开 16 个线程和测 1 个文件开 128 个线程, 测出来 iops 是一样的, 因为它的分配和管理机制都是一样的
那为什么 MySQL4.0 版本开始引入了独立表空间呢?
主要是为了管理方便, 表现为:
看上去清晰
删除文件非常简单, drop 完空间可释放, 对于 ibdata1 来说, 一个文件, 只能增不能减, 删除一张表只是把这张表对应的空间标为可用, 但是空间并不能回收
删除. ibd 文件是不行的, 因为对应的 innodb 元数据表里面的数据没有删
.ibd 和. ibdata1 文件坏了修复的话收费是按行数来算的很贵的哦, 相对而言 ibdata1 文件修复难度更大
切记: 不要在数据目录下删除任何文件
3.4 小常识
单个 ibd 文件直接拷贝到新的数据库中无法直接恢复:
原因一: 元数据信息还是在 ibdata1 中
原因二: 部分索引文件存在于 Change Buffer 中, 目前还是存放于 ibdata1 文件中
查看表空间的元数据信息
select * from information_schema.innodb_sys_tablespaces;
, 逻辑存储结构
4.1 从上到下的结构
表空间 |
---|
内部有多个段对象(Segment)组成 |
每个段(Segment)由区(Extent)组成 |
每个区(Extent)由页(Page)组成 |
每个页里面保存数据(或者叫记录 Row) |
段:
段对用户来说是透明的, 也是一个逻辑的概念, 用来组织管理区
在 MySQL 系统表中是看不到段这个元数据的, 但是逻辑上的确存在(重点理解区和页)
区:
区包含页
区是最小的空间申请单位, 表空间文件要扩展是以区的单位来扩展
区的大小固定为 1M, 这 1M 在物理上是连续的, 但 1M 和 1M 之间不保证连续
page_size=16K 就是 1M * 1024 / 16 = 64 个页
16k 64 个页
8k 128 个页
4k 256 个页
通常一次申请 4 个区大小, 1 兆 1 兆地申请, 特殊情况会申请 5 个区, 很少发生这种情况
页 :
等价于 ORACLE 中的块 , 最小的 I/O 操作单位
tips:
data 的最小单位不是页, 而是页中的记录(row)
普通用户表中 MySQL 默认的每个页为 16K
从 MySQL 5.6 开始使用 innodb_page_size 可以控制页大小
一旦数据库通过 innodb_page_size 创建完成, 则后续无法更改
innodb_page_size 是针对普通表的, 压缩表不受其限制
4.2 来来来, 吹两手
从 5.6 开始可以调整大小, 但只能设置 4k 和 8k, 从 5.7 开始还可以设置 32k,64k, 如果设置为 32k 或者 64k 那区的大小就变为 2M 和 4M
什么淘宝标准 MySQL 配置参数把这个大小设置为 4k, 完全扯淡, 就算在 ssd 下 4k 可能也不会比 16k 好, 另外设置为 4k,io 操作会变多, 不要迷信, 现在的表偏向于宽表(很多列组成, 单行记录比较大), 一行超过 1k 甚至 4k 以上, 这时候这个页大小设为 4, 性能会很差.
设置小了, B+ tree 高度变高, io 变多, 性能变差; 如果是宽列, 4k 的页会导致行外存, 效率变差
目前为止, 大家都用的 SSD, 列比较宽, 内存也比较大, 就保留 16k 或者尝试一下 32k(一些单列特别大的场景, 大页性能有优势)
tips:
MySQL 页大小和 ORACLE 页大小不同的是, MySQL 页大小是全局的, 一旦初始化好, 就不可再修改, 不像 ORACLE 可以设置每张表的页大小
,MySQL 中如何定位到一个页
SpaceID
每个表空间都对应一个 SpaceID, 而表空间又对应一个 ibd 文件, 那么一个 ibd 文件也对应一个 SpaceID
ibdata1 对应的 SpaceID 为 0, 每创建一个表空间(ibd 文件),SpaceID 自增长(全局)
PageNumber
在一个表空间中, 第几个 16K 的页 (假设 innodb_page_size = 16K) 即为 PageNumber
每次读取 Page 时, 都是通过 SpaceID 和 PageNumber 进行读取
可以简单理解为从表空间的开头读多少个 PageNumber * PageSize 的字节(偏移)
想成数组, 数组的名字就是 SpaceID, 数组的下标就是 PageNumber
在一个 SpaceID(ibd 文件)中, PageNumber 是唯一且自增的
删除表的时候, SpaceID 不会回收 ,SpaceID 是全局自增长的
tips:
这里的区 (extent) 的概念已经弱化
在这个例子中, 第一个区的 PageNumber 是 (0 到 63) 且这 64 个页在物理上是连续的; 第二个区的 PageNumber 是(64 到 127) 且这 64 个页在物理上也是连的
但是 (0 到 63) 和(64 到 127)之间在物理上则不一定是连续的, 因为区和区之间在物理上不一定是连续的
随便看看
(root@localhost) [information_schema]> select space, name from information_schema.innodb_sys_tablespaces order by space limit 5;
- +-------+---------------------+
- | space | name |
- +-------+---------------------+
- | 2 | mysql/plugin |
- | 3 | mysql/servers |
- | 4 | mysql/help_topic |
- | 5 | mysql/help_category |
- | 6 | mysql/help_relation |
- +-------+---------------------+
- 5 rows in set (0.00 sec)
- (root@localhost) [information_schema]> select name, space, table_id from information_schema.innodb_sys_tables where space=0;
- +------------------+-------+----------+
- | name | space | table_id |
- +------------------+-------+----------+
- | SYS_DATAFILES | 0 | 14 |
- | SYS_FOREIGN | 0 | 11 |
- | SYS_FOREIGN_COLS | 0 | 12 |
- | SYS_TABLESPACES | 0 | 13 |
- | SYS_VIRTUAL | 0 | 15 |
- +------------------+-------+----------+
- 5 rows in set (0.00 sec)
- (root@localhost) [information_schema]> select name, space, table_id from information_schema.innodb_sys_tables where space<>0 order by space limit 5;
- +---------------------+-------+----------+
- | name | space | table_id |
- +---------------------+-------+----------+
- | mysql/plugin | 2 | 16 |
- | mysql/servers | 3 | 17 |
- | mysql/help_topic | 4 | 35 |
- | mysql/help_category | 5 | 36 |
- | mysql/help_relation | 6 | 38 |
- +---------------------+-------+----------+
- 5 rows in set (0.00 sec)
独立表空间的 table_id 和 SpaceID 一一对应
共享表空间是多个 table_id 对应一个 SpaceID
SpaceID 为 0 的是 ibdata1,1 这个位置没有, 空的
来源: http://www.bubuko.com/infodetail-2587854.html