第15章:存储引擎和表类型 / 15.2. InnoDB存储引擎 / 15.2.14.文件空间管理和磁盘I/O

15.2.14.1. 磁盘I/O

15.2.14.2. 为表空间使用原始设备

15.2.14.3.文件空间管理

15.2.14.4. 整理表碎片

15.2.14.1. 磁盘 I/O

InnoDB使用模拟异步磁盘I/O:InnoDB创建许多线程来处理I/O操作,比如read-ahead.

在InnoDB中有两个read-ahead试探:

·         在连续read-ahead中,如果InnoDB注意到在表空间中对一个片断的访问方式是连续的,它就预先布置一批 数据库页的读 给I/O系统。

·         在随机read-ahead中,如果InnoDB注意到表空间中的一些区域看起来进入完全读进缓冲池中的处理中,它就布置剩余的读到I/O系统。

InnoDB使用一个被称为doublewrite的新颖的文件 刷新技术。它给操作体统崩溃或掉电后的恢复添加了安全,并且通过减少对fsync()操作的需要,它在多数Unix变种上改善了性能。.

Doublewrite意为在向一个数据文件写页之前,InnoDB首先把它们写到一个毗邻的表空间区域,称为doublewrite缓冲。仅在写然后 刷新到doublewrite已经完成之前,InnoDB写页面到它们在表空间中恰当的位置。如果操作系统在写页面的中间崩溃,在恢复过程中,InnoDB可以在随后从doublewrite缓冲中找到页面的一个良好复制。

15.2.14.2. 为表空间使用原始设备

你也可以使用原始磁盘分区作为表空间数据文件。通过使用原始磁盘,你可以在Windows和一些Unix系统上执行non-buffered I/O 而无须文件系统开支,这样可以改善性能

当你创建一个新数据文件之时,你必须在innodb_data_file_path里紧接着数据文件尺寸之后放置 关键字newraw。分区必须至少和你指定的尺寸一样大,注意,在InnoDB中,1MB是1024x1024字节, 但是在磁盘规格中,1MB通常意为1,000,000字节。

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw

下次你启动服务器之时,InnoDB注意到关键字newraw并初始化新分区。但是仍然并不创建或改变任何InnoDB表。另外,当你重启服务器之时,InnoDB重新初始化分区,你的改变会丢失。(从3.23.44启动,作为一个安全措施, 当用newraw指定任何分区之时,InnoDB阻止用户修改数据)。

InnoDB初始化新分区之后,停止服务器,在对行的数据文件规格中改变newraw:

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:5Graw;/dev/hdd2:2Graw

然后重启动服务器,并且InnoDB允许做改变。

在Windows上,你可以象这样分配磁盘分区为一个数据文件:

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=//./D::10Gnewraw

对于访问物理驱动器,//./ 相当于Windows语法的\\.\ 。

当你使用原始磁盘分区之时,确信它们有允许被用来运行MySQL服务器的帐号读和写访问的许可。

15.2.14.3.文件空间管理

你在配置文件中定义的数据文件形成InnoDB的表空间。文件被简单地连起来以形成表空间。没有条纹在使用。当前你不能定义你的表被分配到表空间中的位置。但是,在一个新创建的表中间中,InnoDB 从第一个数据文件开始分配空间。

表空间包含数据库页,默认大小是16KB。这些页被分组成64个连续页的范围。表空间内的文件在InnoDB中被称为片断。术语“rollback segment”有一些混淆,因为它确切地包含许多表空间片断。

在InnoDB中,每个索引分配两个片断。一个是给B树的非树叶节点的,另一个是给树叶节点的。在这里,理想的是为包含数据的树叶节点达到更好的有序性。

当一个片断在表空间内长大,InnoDB单独地分配最先的32页给它。此后InnoDB开始分配整个范围给该片断。InnoDB可以一次给一个大片断添加多达4个范围以确保数据良好的连续性。

在表空间中的一些页包含其它页的位图,因此在一个InnoDB表空间中的一些范围不能被整个地分配给片断,只能作为单个页被分配。

当你发出SHOW TABLE STATUS询问表空间里可用的自由空间之时,InnoDB报告在表空间中完全自由的范围。InnoDB总是为扫除和其它内部目的保留一些范围,这些保留的范围不包括在自由空间里。

当你从一个表中删除数据之时,InnoDB联系相应的B树索引。是否释放单独页或是范围到表空间取决删除的方式,因此被释放的空间变成对其它用户可用,但是记住,已删除的行仅在该行不再被事务 回滚或持续读所需要之后的一个(自动)净化操作中被物理删除。

15.2.14.4. 整理表碎片

如果有随机插入到表的索引或从表的索引随机删除,索引可能变成碎片的。碎片意思是索引页在磁盘上的物理排序并不接近页上记录的索引排序,或者在分配给索引的64页块上有许多没有被使用的页。

碎片的一个“同义词”是一个表占据的空间超过它应该占据的空间的大 小。确切是多少,这是很难去确定的。所有InnoDB数据和索引被存在B树中,并且它们的填充因子可能从50%到100%。碎片的另一个“同 义词”是一个表扫描例如:

SELECT COUNT(*) FROM t WHERE a_non_indexed_column <> 12345;

花了超过它应该花的时间。(在上面的查询中我们“欺骗”SQL优化器来扫描集束索引,而不是一个第二索引 )。多数磁盘可以读10MB/s到50MB/s,这可以被用来评估一个表扫描可以多快地运行。

如果你周期地执行“null” ALTER TABLE操作,它就可以加速索引扫描: 

ALTER TABLE tbl_name ENGINE=INNODB

这导致MySQL重建表。另一个执行碎片整理操作的办法是使用mysqldump来转储一个表到一个文本文件,移除表,并重新从转储文件重装载它。

如果到一个索引的插入总是升序的,并且记录仅从末尾被删除,InnoDB文件空间管理保证在索引中的碎片不会发生。