企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### 第15章:存储引擎和表类型 MySQL支持数个存储引擎作为对不同表的类型的处理器。MySQL存储引擎包括处理事务安全表的引擎和处理非事务安全表的引擎: ·        MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。MyISAM在所有MySQL配置里被支持,它是默认的存储引擎,除非你配置MySQL默认使用另外一个引擎。 ·        MEMORY存储引擎提供“内存中”表。MERGE存储引擎允许集合将被处理同样的MyISAM表作为一个单独的表。就像MyISAM一样,MEMORY和MERGE存储引擎处理非事务表,这两个引擎也都被默认包含在MySQL中。 **注释:**MEMORY存储引擎正式地被确定为HEAP引擎。 ·        InnoDB和BDB存储引擎提供事务安全表。BDB被包含在为支持它的操作系统发布的MySQL-Max二进制分发版里。InnoDB也默认被包括在所有MySQL 5.1二进制分发版里,你可以按照喜好通过配置MySQL来允许或禁止任一引擎。 ·        EXAMPLE存储引擎是一个“存根”引擎,它不做什么。你可以用这个引擎创建表,但没有数据被存储于其中或从其中检索。这个引擎的目的是服务,在MySQL源代码中的一个例子,它演示说明如何开始编写新存储引擎。同样,它的主要兴趣是对开发者。 ·        NDB Cluster是被MySQL Cluster用来实现分割到多台计算机上的表的存储引擎。它在MySQL-Max 5.1二进制分发版里提供。这个存储引擎当前只被Linux, Solaris, 和Mac OS X 支持。在未来的MySQL分发版中,我们想要添加其它平台对这个引擎的支持,包括Windows。 ·        ARCHIVE存储引擎被用来无索引地,非常小地覆盖存储的大量数据。 ·        CSV存储引擎把数据以逗号分隔的格式存储在文本文件中。 ·         BLACKHOLE存储引擎接受但不存储数据,并且检索总是返回一个空集。 ·        FEDERATED存储引擎把数据存在远程数据库中。在MySQL 5.1中,它只和MySQL一起工作,使用MySQL C Client API。在未来的分发版中,我们想要让它使用其它驱动器或客户端连接方法连接到另外的数据源。 寻求选择一个存储引擎的帮助,请参阅[14.4节,“选择一个存储引擎”](# "14.4. Choosing a Storage Engine")。 这一章讲述除NDB Cluster外的每一个MySQL存储引擎,NDB Cluster在[第17章:_MySQL Cluster_](# "Chapter 17. MySQL Cluster")中介绍。 当年创建一个新表的时候,你可以通过添加一个ENGINE 或TYPE 选项到CREATE TABLE语句来告诉MySQL你要创建什么类型的表: CREATE TABLE t (i INT) ENGINE = INNODB; CREATE TABLE t (i INT) TYPE = MEMORY; 虽然TYPE仍然在MySQL 5.1中被支持,现在ENGINE是首选的术语。 如果你省略掉ENGINE或TYPE选项,默认的存储引擎被使用。一般的默认是MyISAM,但你可以用--default-storage-engine或--default-table-type服务器启动选项来改变它,或者通过设置storage_engine或table_type系统变量来改变。 当MySQL被用MySQL配置向导安装在Windows平台上,InnoDB存储引擎替代MyISAM存储引擎作为替代,请参阅[2.3.5.1节,“介绍”](# "2.3.5.1. Introduction")。 要把一个表从一个类型转到另一个类型,可使用ALTER TABLE语句,这个语句指明新的类型: ALTER TABLE t ENGINE = MYISAM; ALTER TABLE t TYPE = BDB; 请参阅[13.1.5节,“CREATE TABLE语法”](# "13.1.5. CREATE TABLE Syntax")和[13.1.2节,“ALTER TABLE语法”](# "13.1.2. ALTER TABLE Syntax")。 如果你试着使用一个未被编译进MySQL的存储引擎,或者试着用一个被编译进MySQL但没有被激活的存储引擎,MySQL取而代之地创建一个MyISAM类型的表。当你在支持不同存储引擎的MySQL服务器之间拷贝表的时候,上述的行为是很方便的。(例如,在一个复制建立中,可能你的主服务器为增加安全而支持事务存储引擎,但从服务器为更快的速度而仅使用非事务存储引擎。) 在不可用的类型被指定时,自动用MyISAM表来替代,这会对MySQL的新用户造成混淆。无论何时一个表被自动改变之时,产生一个警告。 MySQL总是创建一个.frm文件来保持表和列的定义。表的索引和数据可能被存储在一个或多个文件里,这取决于表的类型。服务器在存储引擎级别之上创建.frm文件。单独的存储引擎创建任何需要用来管理表的额外文件。 一个数据库可以包含不同类型的表。 事务安全表(TST) 比起非事务安全表 (NTST)有几大优势: ·        更安全。即使MySQL崩溃或遇到硬件问题,要么自动恢复,要么从备份加事务日志恢复,你可以取回数据。 ·        你可以合并许多语句,并用COMMIT语句同时接受它们全部(如果autocommit被禁止掉)。 ·         你可以执行ROLLBACK来忽略你的改变(如果autocommit被禁止掉)。 ·        如果更新失败,你的所有改变都变回原来。(用非事务安全表,所有发生的改变都是永久的)。 ·        事务安全存储引擎可以给那些当前用读得到许多更新的表提供更好的部署。 虽然MySQL支持数个事务安全存储引擎,为获得最好结果,你不应该在一个事务那混合不同表类型。如果你混合表类型会发生问题,更多信息请参阅[13.4.1节,“START TRANSACTION, COMMIT和ROLLBACK Syntax”](# "13.4.1. START TRANSACTION, COMMIT, and ROLLBACK Syntax")。 如果你没有指定配置值的话,InnoDB使用默认的配置值。请参阅[15.2.3节,“InnoDB配置”](# "15.2.3. InnoDB Configuration")。 非事务安全表自身有几个优点,因为没有事务开支,所有优点都能出现: ·        更快 ·        需要更少的磁盘空间 ·        执行更新需要更少的内存 你可以在同一个语句中合并事务安全和非事务安全表来获得两者最好的情况。尽管如此,在autocommit被禁止掉的事务里,变换到非事务安全表依旧即时提交,并且不会被回滚。 ### 15.1. MyISAM存储引擎 [15.1.1. MyISAM启动选项](#) [15.1.2.键需要的空间](#) [15.1.3. MyISAM表存储格式](#) [15.1.4. MyISAM表的问题](#) MyISAM是默认存储引擎。它基于更老的ISAM代码,但有很多有用的扩展。(注意MySQL 5.1不支持ISAM)。 每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。 要明确表示你想要用一个MyISAM表格,请用ENGINE表选项指出来: CREATE TABLE t (i INT) ENGINE = MYISAM; **注释**:老版本的MySQL使用TYPE而不是ENGINE(例如,TYPE = MYISAM)。MySQL 5.1为向下兼容而支持这个语法,但TYPE现在被轻视,而ENGINE是首先的用法。 一般地,ENGINE选项是不必要的;除非默认已经被改变了,MyISAM是默认存储引擎。 你可以用**myisamchk**工具来检查或修复MyISAM表。请参阅[5.9.5.6节,“使用**myisamchk**做崩溃恢复”](# "5.9.5.6. Using myisamchk for Crash Recovery")。你也可以用**myisampack**来压缩MyISAM表,让它们占更少的空间。请参阅[8.2节,“myisampack,产生压缩、只读的MyISAM表”](# "8.2. myisampack — Generate Compressed, Read-Only MyISAM Tables")。 如下是MyISAM存储引擎的一些特征: ·        所有数据值先存储低字节。这使得数据机和操作系统分离。二进制轻便性的唯一要求是机器使用补码(如最近20年的机器有的一样)和IEEE浮点格式(在主流机器中也完全是主导的)。唯一不支持二进制兼容性的机器是嵌入式系统。这些系统有时使用特殊的处理器。 先存储数据低字节并不严重地影响速度;数据行中的字节一般是未联合的,从一个方向读未联合的字节并不比从反向读更占用更多的资源。服务器上的获取列值的代码与其它代码相比并不显得时间紧。 ·        大文件(达63位文件长度)在支持大文件的文件系统和操作系统上被支持。 ·        当把删除和更新及插入混合的时候,动态尺寸的行更少碎片。这要通过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块来自动完成。 ·        每个MyISAM表最大索引数是64。 这可以通过重新编译来改变。每个索引最大的列数是16个。 ·        最大的键长度是1000字节。这也可以通过编译来改变。对于键长度超过250字节的情况,一个超过1024字节的的键块被用上。 ·        BLOB和TEXT列可以被索引。 ·        NULL值被允许在索引的列中。这个占每个键的0-1个字节。 ·        所有数字键值以高字节为先被存储以允许一个更高地索引压缩。 ·        当记录以排好序的顺序插入(就像你使用一个AUTO_INCREMENT列之时),索引树被劈开以便高节点仅包含一个键。这改善了索引树的空间利用率。 ·        每表一个AUTO_INCREMEN列的内部处理。MyISAM为INSERT和UPDATE操作自动更新这一列。这使得AUTO_INCREMENT列更快(至少10%)。在序列顶的值被删除之后就不能再利用。(当AUTO_INCREMENT列被定义为多列索引的最后一列,可以出现重使用从序列顶部删除的值的情况)。AUTO_INCREMENT值可用ALTER TABLE或**myisamch**来重置。 ·        如果数据文件中间的表没有自由块了,在其它线程从表读的同时,你可以INSERT新行到表中。(这被认识为并发操作)。自由块的出现是作为删除行的结果,或者是用比当前内容多的数据对动态长度行更新的结果。当所有自由块被用完(填满),未来的插入又变成并发。 ·        你可以把数据文件和索引文件放在不同目录,用DATA DIRECTORY和INDEX DIRECTORY选项CREATE TABLE以获得更高的速度,请参阅[13.1.5节,“CREATE TABLE语法”](# "13.1.5. CREATE TABLE Syntax")。 ·        每个字符列可以又不同的字符集,请参阅[第10章:“字符集支持”](# "Chapter 10. Character Set Support")。 ·        在MyISAM索引文件里又一个标志,它表明表是否被正确关闭。如果用--myisam-recover选项启动**mysqld**,MyISAM表在打开得时候被自动检查,如果被表被不恰当地关闭,就修复表。 ·        如果你用--update-state选项运行**myisamchk**,它标注表为已检查。**myisamchk --fast**只检查那些没有这个标志的表。 ·        **myisamchk --analyze**为部分键存储统计信息,也为整个键存储统计信息。 ·        **myisampack**可以打包BLOB和VARCHAR列。 MyISAM也支持下列特征: ·        支持true VARCHAR类型;VARCHAR列以存储在2个字节中的长度来开始。 ·        有VARCHAR的表可以有固定或动态记录长度。 ·        VARCHAR和CHAR列可以多达64KB。 ·         一个被搞乱的已计算索引对可对UNIQUE来使用。这允许你在表内任何列的合并上有UNIQUE。(尽管如此,你不能在一个UNIQUE已计算索引上搜索)。 对MyISAM存储引擎,有一个更详细的论坛在[http://forums.mysql.com/list.php?21](http://forums.mysql.com/list.php?21)。 ### 15.1.1. MyISAM启动选项 下列对**mysqld** 的选项可用来改变MyISAM表的行为: ·        --myisam-recover=_mode_ 设置为崩溃MyISAM表自动恢复的模式。 ·        --delay-key-write=ALL 对任何MyISAM表的写操作之间不要刷新键缓冲区。 **注释:**如果你要这么做。当表在使用中之时,你应该不使用来自另一个程序的MyISAM表(比如从另一个MySQL服务器或用**myisamchk**)。这么做会导致索引被破坏。 对使用--delay-key-write的表,使用--external-locking没有帮助。 请参阅[5.3.1节,“**mysqld**命令行选项”](# "5.3.1. mysqld Command-Line Options")。 下列系统变量影响MyISAM表的行为: ·        bulk_insert_buffer_size 用在块插入优化中的树缓冲区的大小。**注释**:这是一个_per thread_的限制。 ·        (_OBSOLETE_) myisam_max_extra_sort_file_size 这个参数已经不在MySQL中使用。 ·        myisam_max_sort_file_size 如果临时文件会变得超过索引,不要使用快速排序索引方法来创建一个索引。**注释**:这个参数以字节的形式给出。 ·        myisam_sort_buffer_size 设置恢复表之时使用的缓冲区的尺寸。 请参阅[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。 如果用--myisam-recover选项启动**mysqld**,自动恢复被激活。在这种情况下,当服务器打开一个MyISAM表之时,服务器会检查是否表被标注为崩溃,或者表的打开计数变量是否不为0且你正用--skip-external-locking运行服务器。如果这些条件的任何一个为真,下列情况发生: ·        表被查错。 ·        如果服务器发现一个错误,它试着做快速表修复(排序且不重新创建数据文件)。 ·        如果修复因为数据文件中的一个错误而失败(例如,一个重复键错误),服务器会再次尝试修复,这一次重建数据文件。 ·         如果修复仍然失败,服务器用旧修复选项方法再重试一次修复(一行接一行地写,不排序)。这个方法应该能修复任何类型的错误,并且需要很低的磁盘空间。 如果恢复不能够从先前完成的语句里恢复所有行,而且你不能在--myisam-recover选项值指定FORCE,自动修复会终止,并在错误日志里写一条错误信息: Error: Couldn't repair table: test.g00pages 如果你指定FORCE,取而代之地,类似这样的一个警告被给出: Warning: Found 344 of 354 rows when repairing ./test/g00pages 注释:如果自动恢复值包括BACKUP,恢复进程创建文件并用_tbl_name-datetime_.BAK形式取名。你应该有一个**cron**脚本,它自动把这些文件从数据库目录移到备份媒质上。 ### 15.1.2.键所需的空间 MyISAM表使用B型树索引。你可以粗略地计算索引文件的大小为(key_length+4)/0.67, 加上所有的键之和。当所有键以排序的顺序插入并且表没有任何压缩的键之时,以上估计是对最坏的情况的。 字符串索引是被空间压缩的。如果第一个字符串索引部分是字符串,它也被加前缀压缩。如果字符串列有许多拖曳空间,或字符串列是一个总是不用完全长度的VARCHAR列,空间压缩使得索引文件比最坏情况时的数值要小。前缀压缩被用在以字符串开始的键上。如果有许多具有同一前缀的字符串,前缀压缩是有帮助的。 在MyISAM表,你也可以在创建表的时候通过指定PACK_KEYS=1来前缀压缩数字。当数字被以高字节优先存储之时,若你有许多具有同一前缀的整数键,上述方法是有帮助的。 ### 15.1.3. MyISAM表的存储格式 [15.1.3.1. 静态(固定长度)表特征](#) [15.1.3.2. 动态表特征](#) [15.1.3.3. 已压缩表特征](#) MyISAM支持三种不同存储格式。其中两个(固定格式和动态格式)根据正使用的列的类型来自动选择。第三个,即已压缩格式,只能使用**myisampack**工具来创建。 当你CREATE或ALTER一个没有BLOB或TEXT列的表,你可以用ROW_FORMAT表选项强制表的格式为FIXED或DYNAMIC。这会导致CHAR和VARCHAR列因FIXED格式变成CHAR,或因DYNAMIC格式变成VARCHAR。 通过用ALTER TABLE指定ROW_FORMAT={COMPRESSED | DEFAULT},你可以压缩或解压缩表,请参阅[13.1.5节,“CREATE TABLE语法”](# "13.1.5. CREATE TABLE Syntax")。 #### 15.1.3.1. 静态(固定长度)表特征 静态格式是MyISAM表的默认存储格式。当表不包含变量长度列(VARCHAR, BLOB, 或TEXT)时,使用这个格式。每一行用固定字节数存储。 MyISAM的三种存储格式中,静态格式就最简单也是最安全的(至少对于崩溃而言)。静态格式也是最快的on-disk格式。快速来自于数据文件中的行在磁盘上被找到的容易方式:当按照索引中的行号查找一个行时,用行长度乘以行号。同样,当扫描一个表的时候,很容易用每个磁盘读操作读一定数量的记录。 当MySQL服务器正往一个固定格式MyISAM文件写的时候,如果计算机崩溃了,安全是显然的。在这种情况下,**myisamchk**可以容易地决定每行从哪里开始到哪里结束,所以它通常可以收回所有记录,除了写了一部分的记录。注意,基于数据行,MyISAM表索引可以一直被重新构建。 静态格式表的一般特征: ·        CHAR列对列宽度是空间填补的。 ·        非常快。 ·        容易缓存。 ·         崩溃后容易重建,因为记录位于固定位置。 ·        重新组织是不必要的,除非你删除巨量的记录并且希望为操作系统腾出磁盘空间。为此,可使用OPTIMIZE TABLE或者**myisamchk -r**。 ·        通常比动态格式表需要更多的磁盘空间。 #### 15.1.3.2. 动态表特征 如果一个MyISAM表包含任何可变长度列(VARCHAR, BLOB或TEXTDynamic),或者如果一个表被用ROW_FORMAT=DYNAMIC选项来创建,动态存储格式被使用。 这个格式更为复杂一点,因为每行有一个表明行有多长的头。当一个记录因为更新的结果被变得更长,该记录也可以在超过一个位置处结束。 你可以使用OPTIMIZE TABLE或**myisamchk**来对一个表整理碎片。如果在一个表中有你频繁访问或改变的固定长度列,表中也有一些可变长度列,仅为避免碎片而把这些可变长度列移到其它表可能是一个好主意。 动态格式表的一般特征: ·        除了长度少于4的列外,所有的字符串列是动态的。 ·        在每个记录前面是一个位图,该位图表明哪一列包含空字符串(对于字符串列)或者0(对于数字列)。注意,这并不包括包含NULL值的列。如果一个字符列在拖曳空间移除后长度为零,或者一个数字列为零值,这都在位图中标注了且列不被保存到磁盘。 非空字符串被存为一个长度字节加字符串的内容。 ·        通常比固定长度表需要更少的磁盘空间。 ·        每个记录仅使用必需大小的空间。尽管如此,如果一个记录变大,它就按需要被分开成多片,造成记录碎片的后果。比如,你用扩展行长度的信息更新一行,该行就变得有碎片。在这种情况下,你可以时不时运行OPTIMIZE TABLE或**myisamchk -r**来改善性能。可使用**myisamchk -ei**来获取表的统计数据。 ·         动态格式表在崩溃后要比静态格式表更难重建,因为一个记录可能被分为多个碎片且链接(碎片)可能被丢失。 ·        动态尺寸记录期望的行长度用下列表达式来计算: ·                3 ·                + (number of columns + 7) / 8 ·                + (number of char columns) ·                + (packed size of numeric columns) ·                + (length of strings) ·                + (number of NULL columns + 7) / 8 对每个链接需要额外的6字节。在一个更新导致一个记录的扩大之时,一个动态记录被链接了。每个新链接至少是20字节,所以下一个扩大可能在同样的链接里进行。如果不是,则另一个链接将被建立。你可以使用**myisamchk -ed**来找出链接的数目。所有的链接可以用**myisamchk -r**来移除。 #### 15.1.3.3. 已压缩表特征 已压缩存储格式是由**myisampack**工具创建的只读格式。 所有MySQL分发版里都默认包括**myisampack**。已压缩表可以用**myisamchk**来解压缩。 已压缩表有下列特征: ·        已压缩表占据非常小的磁盘空间。这最小化了磁盘用量,当使用缓慢的磁盘(如CD-ROM)之时,这是很有用的。 ·         每个记录是被单独压缩的,所以只有非常小的访问开支。依据表中最大的记录,一个记录的头在每个表中占据1到3个字节。每个列被不同地压缩。通常每个列有一个不同的Huffman树。一些压缩类型如下: o        后缀空间压缩。 -        前缀空间压缩。 -        零值的数用一个位来存储。 -        如果在一个整型列中的值有一个小的范围,列被用最小可能的类型来存储。比如,一个BIGINT列(8字节),如果所有它的值在-128到127范围内,它可以被存储为TINYINT列(1字节) -        如果一个列仅有一小组可能的值,列的类型被转化成ENUM。 -        一个列可以使用先前压缩类型的任意合并。 ·        可以处理固定长度或动态长度记录。 ### 15.1.4. MyISAM表方面的问题 [15.1.4.1. 损坏的MyISAM表](#) [15.1.4.2. 未被适当关闭的表的问题](#) MySQL用来存储数据的文件格式已经被广泛测试过,但总是有导致数据表变得损坏的环境。 #### 15.1.4.1. 损坏的MyISAM表 即使MyISAM表格式非常可靠(SQL语句对表做的所有改变在语句返回之前被写下),如果下列任何事件发生,你依然可以获得损坏的表: ·        **mysqld**进程在写中间被杀掉。 ·        发生未预期的计算机关闭(例如,计算机被关闭)。 ·        硬件故障。 ·        你可以同时在正被服务器修改的表上使用外部程序(如**myisamchk**)。 ·        MySQL或MyISAM代码的软件缺陷。 一个损坏的表的典型症状如下: ·        当在从表中选择数据之时,你得到如下错误: ·                Incorrect key file for table: '...'. Try to repair it ·        查询不能在表中找到行或返回不完全的数据。 你可以用CHECK TABLE statement语句来检查MyISAM表的健康,并用REPAIR TABLE修复一个损坏的MyISAM表。当**mysqld**不运行之时,你也可以用**myisamchk**命令检查或修理一个表。请参阅[13.5.2.3节,“CHECK TABLE语法”](# "13.5.2.3. CHECK TABLE Syntax"), [13.5.2.6节,“REPAIR TABLE语法”](# "13.5.2.6. REPAIR TABLE Syntax"),和[5.9.5节,“myisamchk — MyISAM表维护工具”](# "5.9.5. myisamchk — MyISAM Table-Maintenance Utility")。 如果你的表变得频繁损坏,你应该试着确定为什么会这样的原因。要明白的最重要的事是表变得损坏是不是因为服务器崩溃的结果。你可以在错误日志中查找最近的restarted mysqld消息来早期验证这个。如果存在这样一个消息,则表损坏是服务器死掉的一个结果是很有可能的。否则,损坏可能在正常操作中发生。这是一个缺陷。你应该试着创建一个展示这个问题的可重复生成的测试案例。请参阅[A.4.2节,“如果MySQL保持崩溃,该怎么做”](# "A.4.2. What to Do If MySQL Keeps Crashing") 及[E.1.6节,“如果出现表崩溃,请生成测试案例”](# "E.1.6. Making a Test Case If You Experience Table Corruption")。 #### 15.1.4.2. 未被适当关闭的表的问题 每个MyISAM索引文件(.MYI)在头有一个计数器,它可以被用来检查一个表是否被恰当地关闭。如果你从CHECK TABLE或**myisamchk**得到下列警告,意味着这个计数器已经不同步了: clients are using or haven't closed the table properly 这个警告并不是完全意味着表已被破坏,但你至少应该检查表。 计数器的工作方式如下: ·        表在MySQL中第一次被更新,索引文件头的计数器加一。 ·        在未来的更新中,计数器不被改变。 ·        当表的最后实例被关闭(因为一个操作FLUSH TABLE或因为在表缓冲区中没有空间)之时,若表已经在任何点被更新,则计数器减一。 ·        当你修理或检查表并且发现表完好之时,计数器被重置为零。 ·        要避免与其它可能检查表的进程进行事务的问题,若计数器为零,在关闭时计数器不减一。 换句话来说,计数器只有在下列情况会不同步: ·        MyISAM表不随第一次发出的LOCK TABLES和FLUSH TABLES被复制。 ·        MySQL在一次更新和最后关闭之间崩溃(注意,表可能依然完好,因为MySQL总是在每个语句之间为每件事发出写操作)。 ·        一个表被**myisamchk --recover**或**myisamchk --update-state**修改,同时被**mysqld**使用。 ·        多个**mysqld**服务器正使用表,并且一个服务器在一个表上执行REPAIR TABLE或CHECK TABLE,同时该表也被另一个服务器使用。在这个结构中,使用CHECK TABLE是安全的,虽然你可能从其它服务器上得到警告。尽管如此,REPAIR TABLE应该被避免,因为当一个服务器用一个新的数据文件替代旧的之时,这并没有发送信号到其它服务器上。 总的来说,在多服务器之间分享一个数据目录是一个坏主意。请参阅[5.12节,“在同一个机器上运行多个MySQL服务器”](# "5.12. Running Multiple MySQL Servers on the Same Machine") 获得更多地讨论 ### 15.2. InnoDB存储引擎 [15.2.1. InnoDB概述](#) [15.2.2. InnoDB联系信息](#) [15.2.3. InnoDB配置](#) [15.2.4. InnoDB启动选项](#) [15.2.5. 创建InnoDB表空间](#) [15.2.6. 创建InnoDB表](#) [15.2.7. 添加和删除InnoDB数据和日志文件](#) [15.2.8. InnoDB数据库的备份和恢复atabase](#) [15.2.9. 把InnoDB数据库移到另一台机器上](#) [15.2.10. InnoDB事务模型和锁定](#) [15.2.11. InnoDB性能调节提示](#) [15.2.12. 多版本的实施](#) [15.2.13. 表和索引结构](#) [15.2.14.文件空间管理和磁盘I/O](#) [15.2.15. InnoDB错误处理](#) [15.2.16. 对InnoDB表的限制](#) [15.2.17. InnoDB故障诊断和排除](#) ### 15.2.1. InnoDB概述 InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读。这些特色增加了多用户部署和性能。没有在InnoDB中扩大锁定的需要,因为在InnoDB中行级锁定适合非常小的空间。InnoDB也支持FOREIGN KEY强制。在SQL查询中,你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也可以混合。 InnoDB是为处理巨大数据量时的最大性能设计。它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。 InnoDB存储引擎被完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。这与MyISAM表不同,比如在MyISAM表中每个表被存在分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上。 InnoDB默认地被包含在MySQL二进制分发中。Windows Essentials installer使InnoDB成为Windows上MySQL的默认表。 InnoDB被用来在众多需要高性能的大型数据库站点上产生。著名的Internet新闻站点Slashdot.org运行在InnoDB上。Mytrix, Inc.在InnoDB上存储超过1TB的数据,还有一些其它站点在InnoDB上处理平均每秒800次插入/更新的负荷。 InnoDB在和MySQL一样在同一个GNU GPL证书,第2版(1991年6月版)下发行。更多有关MySQL证书的信息,请参阅[http://www.mysql.com/company/legal/licensing/](http://www.mysql.com/company/legal/licensing/)。 关于InnoDB存储引擎,在[http://forums.mysql.com/list.php?22](http://forums.mysql.com/list.php?22)有一个详细的论坛。 ### 15.2.2. InnoDB联系信息 InnoDB引擎的厂家的联系信息,Innobase Oy的联系方式如下: Web site: http://www.innodb.com/ Email: <sales@innodb.com> Phone: +358-9-6969 3250 (office)        +358-40-5617367 (mobile)   Innobase Oy Inc. World Trade Center Helsinki Aleksanterinkatu 17 P.O.Box 800 00101 Helsinki Finland ### 15.2.3. InnoDB配置 InnoDB存储引擎是默认地被允许的。如果你不想用InnoDB表,你可以添加skip-innodb选项到MySQL选项文件。 被InnoDB存储引擎管理的两个重要的基于磁盘的资源是InnoDB表空间数据文件和它的日志文件。 如果你指定无InnoDB配置选项,MySQL将在MySQL数据目录下创建一个名为ibdata1的10MB大小的自动扩展数据文件,以及两个名为ib_logfile0和ib_logfile1的5MB大小的日志文件。 **注释**:InnoDB给MySQL提供具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。如果拟运行的操作系统和硬件不能如广告说的那样运行,InnoDB**就不能实现如上能力**。许多操作系统或磁盘子系统可能为改善性能而延迟或记录写操作。在一些操作系统上,就是系统调用(fsync()) 也要等着,直到所有未写入已被刷新文件的数据在被刷新到稳定内存之前可以确实返回了。因为这个,操作系统崩溃或掉电可能损坏当前提交的数据,或者在最坏的 情况,因为写操作已被记录了,甚至破坏了数据库。如果数据完整性对你很重要,你应该在用任何程序于生产中之前做一些“pull-the-plug”测试。Mac OS X 10.3 及以后版本,InnoDB使用一个特别的fcntl()文件刷新方法。在Linux下,建议**禁止回写缓存。** 在ATAPI硬盘上,一个类似hdparm -W0 /dev/_hda_命令可能起作用。**小心某些驱动器或者磁盘控制器可能不能禁止回写缓存。** **注释**:要获得好的性能,你应该如下面例子所讨论那样,明确提供InnoDB参数。自然地,你应该编辑设置来适合你的硬件和要求。 要建立InnoDB表空间文件,在my.cnf选项文件里的[mysqld]节里使用innodb_data_file_path选项。在Windows上,你可以替代地使用my.ini文件。innodb_data_file_path的值应该为一个或多个数据文件规格的列表。如果你命名一个以上的数据文件,用 分号(‘;’)分隔它们: innodb_data_file_path=datafile_spec1[;datafile_spec2]... 例如:把明确创建的具有相同特征的表空间作为默认设置的设置操作如下: [mysqld] innodb_data_file_path=ibdata1:10M:autoextend 这个设置配置一个可扩展大小的尺寸为10MB的单独文件,名为ibdata1。没有给出文件的位置,所以默认的是在MySQL的数据目录内。 尺寸大小用M或者G后缀来指定说明单位是MB或者GB。 一个表空间,它在数据目录里包含一个名为ibdata1的固定尺寸50MB的数据文件和一个名为ibdata2大小为50MB的自动扩展文件,其可以像这样被配置: [mysqld] innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend 一个指定数据文件的完全后缀包括文件名,它的尺寸和数个可选属性: file_name:file_size[:autoextend[:max:max_file_size]] autoextend属性和后面跟着的属性只可被用来对innodb_data_file_path行里最后一个数据文件。 如果你对最后的数据文件指定autoextend选项。如果数据文件耗尽了表空间中的自由空间,InnoDB就扩展数据文件。扩展的幅度是每次8MB。 如果磁盘已满,你可能想要把其它数据添加到另一个硬盘上。重新配置一个已存在表空间的指令见[15.2.7节,“添加和删除InnoDB数据和日志文件”](# "15.2.7. Adding and Removing InnoDB Data and Log Files")。 InnoDB并不感知最大文件尺寸,所以要小心文件系统,在那上面最大的文件尺寸是2GB。要为一个自动扩展数据文件指定最大尺寸,请使用max属性。下列配置允许ibdata1涨到极限的500MB: [mysqld] innodb_data_file_path=ibdata1:10M:autoextend:max:500M InnoDB默认地在MySQL数据目录创建表空间文件。要明确指定一个位置,请使用innodb_data_home_dir选项。比如,要使用两个名为ibdata1和ibdata2的文件,但是要把他们创建到/ibdata,像如下一样配置InnoDB: [mysqld] innodb_data_home_dir = /ibdata innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend **注释**:InnoDB不创建目录,所以在启动服务器之前请确认/ibdata目录的确存在。这对你配置的任何日志文件目录来说也是真实的。使用Unix或DOS的mkdir命令来创建任何必需的目录。 通过把innodb_data_home_dir的值原原本本地部署到数据文件名,并在需要的地方添加斜杠或反斜杠,InnoDB为每个数据文件形成目录路径。如果innodb_data_home_dir选项根本没有在my.cnf中提到,默认值是“dot”目录 ./,这意思是MySQL数据目录。 如果你指定innodb_data_home_dir为一个空字符串,你可以为列在innodb_data_file_path值里的数据文件指定绝对路径。下面的例子等价于前面那个例子: [mysqld] innodb_data_home_dir = innodb_data_file_path=/ibdata/ibdata1:50M;/ibdata/ibdata2:50M:autoextend **一个简单的****my.cnf****例子。**假设你有一台配备128MB内存和一个硬盘的计算机。下面的例子显示在my.cnf或my.ini里对InnoDB可能的配置参数,包括autoextend属性。 这个例子适合大多数在Unix和Windows上,不想分配InnoDB数据文件和日志文件到数个磁盘上的用户。它在MySQL数据目录创建一个自动扩展数据文件ibdata1和两个日志文件ib_logfile0及ib_logfile1。同样,InnoD在数据目录里自动创建的小型档案InnoDB日志文件ib_arch_log_0000000000也结束。 [mysqld] # You can write your other MySQL server options here # ... # Data files must be able to hold your data and indexes. # Make sure that you have enough free disk space. innodb_data_file_path = ibdata1:10M:autoextend # # Set buffer pool size to 50-80% of your computer's memory set-variable = innodb_buffer_pool_size=70M set-variable = innodb_additional_mem_pool_size=10M # # Set the log file size to about 25% of the buffer pool size set-variable = innodb_log_file_size=20M set-variable = innodb_log_buffer_size=8M # innodb_flush_log_at_trx_commit=1 请确认MySQL服务器有适当的权限在数据目录里创建文件。更一般地,服务器必须对任何它需要创建数据文件或日志文件的目录有访问权限。 注意,在一些文件系统上,数据文件必需小于2GB。数据文件的合并尺寸必须至少10MB。 当你第一次创建一个InnoDB表空间,最好从命令行来启动MySQL服务器。InnoDB然后把数据库创建的信息打印到屏幕,所以你可以看见正在发生什么。比如,在Windows上,如果**mysqld-max**位于C:\mysql\bin,你可以如下来启动它: C:\> C:\mysql\bin\mysqld-max --console 如果你不发送服务器输出到屏幕上,请检查服务器的错误日志来看在启动过程中InnoDB打印了什么。 请参阅[15.2.5节,“创建InnoDB表空间”](# "15.2.5. Creating the InnoDB Tablespace"),以获得InnoDB显示的信息看起来应该像什么的例子。 **Windows上如何指定选项?** 在Windows上选项文件的规则如下: ·        只应该创建一个my.cnf或文件。 ·        my.cnf文件应该被放在C盘根目录。 ·        my.ini文件应该被放置在WINDIR目录;例如C:\WINDOWS或C:\WINNT。你可以在Windows控制台的命令提示符使用SET命令来打印WINDIR的值: ·                C:\> SET WINDIR ·                windir=C:\WINNT ·        如果你的PC在C盘不是启动盘的地方使用启动装载机,你唯一的选择是使用my.ini文件。 ·         如果你使用安装和配置向导安装的MySQL,my.ini文件被放在MySQL的安装目录。请参阅[2.3.5.14节,“my.ini文件的位置”](# "2.3.5.14. The Location of the my.ini File")。 **Unix上在哪里指定选项?** 在Unix上,**mysqld**从下列文件,如果它们存在的话。以下列的顺序读取选项: ·        /etc/my.cnf 全局选项。 ·        $MYSQL_HOME/my.cnf 服务器专用选项。 ·        defaults-extra-file --defaults-extra-file选项指定的文件。 ·        ~/.my.cnf 用户专用选项。 MYSQL_HOME代表环境变量,它内含着到包含服务器专用my.cnf文件的目录的路径。 如果你确信**mysqld**只从指定文件读取选项,你可以在启动服务器之时在命令行使用--defaults-option作为第一个选项: mysqld --defaults-file=your_path_to_my_cnf **一个高级的****my.cnf****例子。**假设你有一台Linux计算机,有2GB内存和三个60GB硬盘(在目录路径/, /dr2和/dr3)。下列例子显示了在my.cnf里对InnoDB可能的配置参数。 [mysqld] # You can write your other MySQL server options here # ... innodb_data_home_dir = # # Data files must be able to hold your data and indexes innodb_data_file_path = /ibdata/ibdata1:2000M;/dr2/ibdata/ibdata2:2000M:autoextend # # Set buffer pool size to 50-80% of your computer's memory, # but make sure on Linux x86 total memory usage is < 2GB innodb_buffer_pool_size=1G innodb_additional_mem_pool_size=20M innodb_log_group_home_dir = /dr3/iblogs # innodb_log_files_in_group = 2 # # Set the log file size to about 25% of the buffer pool size innodb_log_file_size=250M innodb_log_buffer_size=8M # innodb_flush_log_at_trx_commit=1 innodb_lock_wait_timeout=50 # # Uncomment the next lines if you want to use them #innodb_thread_concurrency=5 注意,该例子把两个数据文件放在不同磁盘上。InnoDB开始用第一个数据文件填充表空间。在一些情况下,如果所有数据不被放置在同一物理磁盘上,这样将改善数据库的性能。把日志文件放在与数据文件不同的磁盘上对性能是经常很有好处的。你也可以使用原始磁盘分区(原始设备)作为InnoDB数据文件,这样可以加速I/O。请参阅[15.2.14.2节,“为表空间使用原始设备”](# "15.2.14.2. Using Raw Devices for the Tablespace")。 **警告**:在32位GNU/Linux x86上,你必须要小心不要设置过高的内存用量。glibc可能允许进程堆积在线程堆栈上发展,它会造成你的服务器崩溃。如果下列表达式的值接近或者超过2GB,系统会面临危机: innodb_buffer_pool_size + key_buffer_size + max_connections*(sort_buffer_size+read_buffer_size+binlog_cache_size) + max_connections*2MB 每个线程使用一个堆栈(通常是2MB,但在MySQL AB二进制分发版里只有256KB)并且在最坏的情况下也使用sort_buffer_size + read_buffer_size附加内存。 你可以自己编译MySQL,在32位Windows上使用高达64GB物理内存。请参阅[15.2.4节,“InnoDB启动选项”](# "15.2.4. InnoDB Startup Options")里对innodb_buffer_pool_awe_mem_mb的描述。 **如何调整其它mysqld服务器参数?**下列值是典型的,且适用于多数用户: [mysqld] skip-external-locking max_connections=200 read_buffer_size=1M sort_buffer_size=1M # # Set key_buffer to 5 - 50% of your RAM depending on how much # you use MyISAM tables, but keep key_buffer_size + InnoDB # buffer pool size < 80% of your RAM key_buffer_size=value ### 15.2.4. InnoDB启动选项 这一节叙述InnoDB相关的服务器选项,所有这些选项可以以--_opt_name_=_value_的形式在命令行或在选项文件里被指定。 ·        innodb_additional_mem_pool_size InnoDB用来存储数据目录信息&其它内部数据结构的内存池的大小。你应用程序里的表越多,你需要在这里分配越多的内存。如果InnoDB用光了这个池内的内存,InnoDB开始从操作系统分配内存,并且往MySQL错误日志写警告信息。默认值是1MB。 ·        innodb_autoextend_increment 当自动扩展表空间被填满之时,为扩展而增加的尺寸(MB为单位)。默认值是8。这个选项可以在运行时作为全局系统变量而改变。 ·        innodb_buffer_pool_awe_mem_mb 如果缓冲池被放在32位Windows的AWE内存里,这个参数就是缓冲池的大小(MB为单位)。(仅在32位Windows上相关)如果你的32位Windows操作系统使用所谓的“地址窗口扩展(AWE)”支持超过4GB内存,你可以用这个参数把InnoDB缓冲池分配进AWE物理内存。这个参数最大的可能值是64000。如果这个参数被指定了,innodb_buffer_pool_size是在32位地址空间的**mysqld**内的窗口,InnoDB把那个AWE内存映射上去。对innodb_buffer_pool_size参数,一个比较好的值是500MB。 ·        innodb_buffer_pool_size InnoDB用来缓存它的数据和索引的内存缓冲区的大小。你把这个值设得越高,访问表中数据需要得磁盘I/O越少。在一个专用的数据库服务器上,你可以设置这个参数达机器物理内存大小的80%。尽管如此,还是不要把它设置得太大,因为对物理内存的竞争可能在操作系统上导致内存调度。 ·        innodb_checksums InnoDB在所有对磁盘的页面读取上使用校验和验证以确保额外容错防止硬件损坏或数据文件。尽管如此,在一些少见的情况下(比如运行标准检查之时)这个额外的安全特征是不必要的。在这些情况下,这个选项(默认是允许的)可以用--skip-innodb-checksums来关闭。 ·        innodb_data_file_path 到单独数据文件和它们尺寸的路径。通过把innodb_data_home_dir连接到这里指定的每个路径,到每个数据文件的完整目录路径可被获得。文件大小通过给尺寸值尾加M或G以MB或者GB(1024MB)为单位被指定。文件尺寸的和至少是10MB。在一些操作系统上,文件必须小于2GB。如果你没有指定innodb_data_file_path,开始的默认行为是创建一个单独的大小10MB名为ibdata1的自扩展数据文件。在那些支持大文件的操作系统上,你可以设置文件大小超过4GB。你也可以使用原始磁盘分区作为数据文件,请参阅[15.2.14.2节,“为表空间使用原始设备”](# "15.2.14.2. Using Raw Devices for the Tablespace")。 ·        innodb_data_home_dir 目录路径对所有InnoDB数据文件的共同部分。如果你不设置这个值,默认是MySQL数据目录。你也可以指定这个值为一个空字符串,在这种情况下,你可以在innodb_data_file_path中使用绝对文件路径。 ·        innodb_doublewrite 默认地,InnoDB存储所有数据两次,第一次存储到doublewrite缓冲,然后存储到确实的数据文件。这个选项可以被用来禁止这个功能。类似于innodb_checksums,这个选项默认是允许的;因为标准检查或在对顶级性能的需要超过对数据完整性或可能故障的关注之时,这个选项用--skip-innodb-doublewrite来关闭。 ·        innodb_fast_shutdown 如果你把这个参数设置为0,InnoDB在关闭之前做一个完全净化和一个插入缓冲合并。这些操作要花几分钟时间,设置在极端情况下要几个小时。如果你设置这个参数为1,InnoDB在关闭之时跳过这些操作。默认值为1。如果你设置这个值为2 (在Netware无此值), InnoDB将刷新它的日志然后冷关机,仿佛MySQL崩溃一样。已提交的事务不会被丢失,但在下一次启动之时会做一个崩溃恢复。 ·        innodb_file_io_threads InnoDB中文件I/O线程的数量。正常地,这个参数是用默认的,默认值是4,但是大数值对Windows磁盘I/O有益。在Unix上,增加这个数没有效果,InnoDB总是使用默认值。 ·        innodb_file_per_table 这个选项致使InnoDB用自己的.ibd文件为存储数据和索引创建每一个新表,而不是在共享表空间中创建。请参阅[15.2.6.6节,“使用Per-Table表空间”](# "15.2.6.6. Using Per-Table Tablespaces")。 ·        innodb_flush_log_at_trx_commit 当innodb_flush_log_at_trx_commit被 设置为0,日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新,但是在一个事务提交不做任何操作。当这个值为1(默认值)之时,在每个事务提交时,日志缓冲被写到日志文件,对日志文件做到磁盘操作的刷新。当设置为2之时,在每个提交,日志缓冲被写到文件,但不对日志文件做到磁盘操作的刷新。尽管如此,在对日志文件的刷新在值为2的情况也每秒发生一次。我们必须注意到,因为进程安排问题,每秒一次的刷新不是100%保证每秒都发生。你可以通过设置这个值不为1来获得较好的性能,但随之你会在一次崩溃中损失二分之一价值的事务。如果你设置这个值为0,那么任何**mysqld**进程的崩溃会删除崩溃前最后一秒的事务,如果你设置这个值为2,那么只有操作系统崩溃或掉电才会删除最后一秒的事务。尽管如此,InnoDB的崩溃恢复不受影响,而且因为这样崩溃恢复开始作用而不考虑这个值。注意,许多操作系统和一些磁盘硬件会欺骗刷新到磁盘操作。尽管刷新没有进行,你可以告诉**mysqld**刷新已经进行。即使设置这个值为1,事务的持久程度不被保证,且在最坏情况下掉电甚至会破坏InnoDB数据库。在SCSI磁盘控制器中,或在磁盘自身中,使用有后备电池的磁盘缓存会加速文件刷新并且使得操作更安全。你也可以试着使用Unix命令**hdparm**来在硬件缓存中禁止磁盘写缓存,或使用其它一些对硬件提供商专用的命令。这个选项的默认值是1。 ·        innodb_flush_method 这个选项只在Unix系统上有效。如果这个选项被设置为fdatasync (默认值),InnoDB使用fsync()来刷新数据和日志文件。如果被设置为O_DSYNC,InnoDB使用O_SYNC来打开并刷新日志文件,但使用fsync()来刷新数据文件。如果O_DIRECT被指定了(在一些GNU/Linux版本商可用),InnoDB使用O_DIRECT来打开数据文件,并使用fsync()来刷新数据和日志文件。注意,InnoDB使用fsync()来替代fdatasync(),并且它默认不使用O_DSYNC,因为这个值在许多Unix变种上已经发生问题。 ·        innodb_force_recovery 警告:这个选项仅在一个紧急情况下被定义,当时你想要从损坏的数据库转储表。可能的值为从1到6。这些值的意思在[15.2.8.1节,“强制恢复”](# "15.2.8.1. Forcing Recovery")中叙述。作为一个安全措施,当这个选项值大于零之时,InnoDB阻止用户修改数据。 ·        innodb_lock_wait_timeout InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒。 为在一个复制建立中最大可能的持久程度和连贯性,你应该在主服务器上的my.cnf文件里使用innodb_flush_log_at_trx_commit=1和sync-binlog=1。 ·        innodb_locks_unsafe_for_binlog 这个选项在InnoDB搜索和索引扫描中关闭下一键锁定。这个选项的默认值是假(false)。 正常地,InnoDB使用一个被称为_next-key locking_的算法。当搜索或扫描一个表索引之时,InnoDB以这样一种方式实行行级锁定,它对任何遇到的索引记录设置共享的或独占的锁定。因此,行级锁定实际是索引记录锁定。InnoDB对索引记录设置的锁定也影响被锁定索引记录之前的“gap”。如果一个用户对某一索引内的记录_R_又共享的或独占的锁定,另一个用户不能立即在_R_之前以索引的顺序插入一个新的索引记录。这个选项导致InnoDB不在搜索或索引扫描中使用下一键锁定。下一键锁定仍然被用来确保外键强制及重复键核查。注意,使用这个选项可能会导致一些诡异的问题:假设你想要用值大于100的标识符从子表里读取并锁定所有的子记录,同时向随后在选定的行更新一些列: SELECT * FROM child WHERE id > 100 FOR UPDATE; 假设在id列有一个索引。查询从id大于100的第一个记录开始扫描索引。如果在索引记录上的锁定不把在间隙处生成的插入排除锁定,同时一个新行被插进表中。如果你在同一个事务之内执行同样的SELECT,你会在查询返回的结果包里看到一个新行。这也意味着,如果新条目被加进数据库,InnoDB不保证连续性;尽管如此,对应连续性仍被保证。因此,如果这个选项被使用,InnoDB在大多数孤立级别保证READ COMMITTED。 这个选项甚至更不安全。InnoDB在一个UPDATE或DELETE中只锁定它更新或删除的行。这大大减少了死锁的可能性,但是可以发生死锁。注意,即使在当类似的操作影响不同行时的情况下,这个选项仍然不允许诸如UPDATE这样的操作压倒相似选项(比如另一个UPDATE)。考虑下列例子: CREATE TABLE A(A INT NOT NULL, B INT); INSERT INTO A VALUES (1,2),(2,3),(3,2),(4,3),(5,2); COMMIT; 如果一个连接执行一个查询: SET AUTOCOMMIT = 0; UPDATE A SET B = 5 WHERE B = 3; 并且其它连接跟着第一个连接执行其它查询: SET AUTOCOMMIT = 0; UPDATE A SET B = 4 WHERE B = 2; 接着查询2要等查询1的提交或回滚,因为查询1对行(2,3)有一个独占的锁定,并且查询2在扫描行的同时也试着对它不能锁定的同一个行(2,3)采取一个独占的锁定。这是因为当innodb_locks_unsafe_for_binlog选项被使用之时,查询2首先对一个行采取一个独占的锁定,然后确定是否这个行属于结果包,并且如果不属于,就释放不必要的锁定。 因此,查询1按如下执行: x-lock(1,2) unlock(1,2) x-lock(2,3) update(2,3) to (2,5) x-lock(3,2) unlock(3,2) x-lock(4,3) update(4,3) to (4,5) x-lock(5,2) unlock(5,2) 并且查询2按如下执行: x-lock(1,2) update(1,2) to (1,4) x-lock(2,3) - 等待查询1提交或回滚 ·        innodb_log_arch_dir 如果我们使用日志档案,被完整写入的日志文件所在的目录也被归档。这个参数值如果被使用了,应该被设置得与innodb_log_group_home_dir一样。尽管如此,它不是必需的。 ·        innodb_log_archive 这个值当前被设为0。因为MySQL使用它自己的日志文件从备份来恢复,所以当前没有必要来归档InnoDB日志文件。这个选项的默认值是0。 ·        innodb_log_buffer_size InnoDB用来往磁盘上的日志文件写操作的缓冲区的大小。明智的值是从1MB到8MB。默认的是1MB。一个大的日志缓冲允许大型事务运行而不需要在事务提交之前往磁盘写日志。因此,如果你有大型事务,使日志缓冲区更大以节约磁盘I/O。 ·        innodb_log_file_size 在日志组里每个日志文件的大小。在32位计算机上日志文件的合并大小必须少于4GB。默认是5MB。明智的值从1MB到_N_分之一缓冲池大小,其中_N_是组里日志文件的数目。值越大,在缓冲池越少需要检查点刷新行为,以节约磁盘I/O。但更大的日志文件也意味这在崩溃时恢复得更慢。 ·        innodb_log_files_in_group 在日志组里日志文件的数目。InnoDB以循环方式写进文件。默认是2(推荐)。 ·        innodb_log_group_home_dir 到InnoDB日志文件的目录路径。它必须有和innodb_log_arch_dir一样的值。如果你不指定任何InnoDB日志参数,默认的是在MySQL数据目录里创建两个5MB大小名为ib_logfile0和ib_logfile1的文件。 ·        innodb_max_dirty_pages_pct 这是一个范围从0到100的整数。默认是90。InnoDB中的主线程试着从缓冲池写页面,使得脏页(没有被写的页面)的百分比不超过这个值。如果你有SUPER权限,这个百分比可以在服务器运行时按下面来改变: SET GLOBAL innodb_max_dirty_pages_pct = value; ·        innodb_max_purge_lag 这个选项控制在净化操作被滞后之时,如何延迟INSERT, UPDATE和DELETE操作。(请参阅[15.2.12节,“多版本的实施”](# "15.2.12. Implementation of Multi-Versioning"))。这个参数的默认值是零,意为无延迟。这个选项可以在运行时作为全局系统变量而被改变。 InnoDB事务系统维持一个事务列表,该列表有被UPDATE或DELETE操作标志为删除的索引记录。让这个列表的长度为_purge_lag_。当_purge_lag_超过innodb_max_purge_lag之时,每个INSERT, UPDATE和DELETE操作延迟 ((_purge_lag_/innodb_max_purge_lag)*10)-5毫秒。在净化批处理的开始,延迟每隔10秒计算。如果因为一个旧的可以看到行被净化的一致的读查看,删除操作不被延迟。 对有问题的工作量,典型设置可能是1百万,假设我们的事务很小,只有100字节大小,我们就可以允许在我们的表之中有100MB未净化的行。 ·        innodb_mirrored_log_groups 我们为数据库保持的日志组内同样拷贝的数量。当前这个值应该被设为1。 ·        innodb_open_files 在InnoDB中,这个选项仅与你使用多表空间时有关。它指定InnoDB一次可以保持打开的.ibd文件的最大数目。最小值是10。默认值300。 对.ibd文件的文件描述符是仅对InnoDB的。它们独立于那些由--open-files-limit服务器选项指定的描述符,且不影响表缓存的操作。 ·        innodb_status_file 这个选项让InnoDB为周期的SHOW INNODB STATUS输出创建一个文件_<datadir>_/innodb_status._<pid>_。 ·        innodb_support_xa 当被设置为ON或者1(默认地),这个变量允许InnoDB支持在XA事务中的双向提交。允许innodb_support_xa导致一个额外的对事务准备的磁盘刷新。如果你对使用XA并不关心,你可以通过设置这个选项为OFF或0来禁止这个变量,以减少磁盘刷新的次数并获得更好的InnoDB性能。 ·        innodb_table_locks InnoDB重视LOCK TABLES,直到所有其它线程已经释放他们所有对表的锁定,MySQL才从LOCK TABLE .. WRITE返回。默认值是1,这意为LOCK TABLES让InnoDB内部锁定一个表。在使用AUTOCOMMIT=1的应用里,InnoDB的内部表锁定会导致死锁。你可以在my.cnf文件(Windows上是my.ini文件)里设置innodb_table_locks=0 来消除这个问题。 ·        innodb_thread_concurrency InnoDB试着在InnoDB内保持操作系统线程的数量少于或等于这个参数给出的限制。如果有性能问题,并且SHOW INNODB STATUS显示许多线程在等待信号,可以让线程“thrashing” ,并且设置这个参数更小或更大。如果你的计算机有多个处理器和磁盘,你可以试着这个值更大以更好地利用计算机的资源。一个推荐的值是系统上处理器和磁盘的个数之和。值为500或比500大会禁止调用并发检查。默认值是20,并且如果设置大于或等于20,并发检查将被禁止。 ·        innodb_status_file 这个选项让InnoDB为周期的SHOW INNODB STATUS输出创建一个文件_<datadir>_/innodb_status._<pid>_。 ### 15.2.5. 创建InnoDB表空间 [15.2.5.1. 处理InnoDB初始化问题](#) 假设你已经安装了MySQL,并且已经编辑了选项文件,使得它包含必要的InnoDB配置参数。在启动MySQL之前,你应该验证你为InnoDB数据文件和日志文件指定的目录是否存在,并且MySQL有访问这些目录的权限。InnoDB不能创建目录,只能创建文件。也检查你有足够的空间来放数据和日志文件。 当创建InnoDB数据库时,最好从命令提示符运行MySQL服务器**mysqld**, 而不要从**mysqld_safe**包装或作为Windows的服务来运行。当你从命令提示符运行,你可看见**mysqld**打印什么以及发生了什么。在Unix上,只需要调用**mysqld**。在Windows上,使用--console选项。 当在选项文件里初始地配置InnoDB后,开始启动MySQL服务器之时,InnoDB创建一个数据文件和日志文件。InnoDB打印如下一些东西: InnoDB: The first specified datafile /home/heikki/data/ibdata1 did not exist: InnoDB: a new database to be created! InnoDB: Setting file /home/heikki/data/ibdata1 size to 134217728 InnoDB: Database physically writes the file full: wait... InnoDB: datafile /home/heikki/data/ibdata2 did not exist: new to be created InnoDB: Setting file /home/heikki/data/ibdata2 size to 262144000 InnoDB: Database physically writes the file full: wait... InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist: new to be created InnoDB: Setting log file /home/heikki/data/logs/ib_logfile0 size to 5242880 InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist: new to be created InnoDB: Setting log file /home/heikki/data/logs/ib_logfile1 size to 5242880 InnoDB: Doublewrite buffer not found: creating new InnoDB: Doublewrite buffer created InnoDB: Creating foreign key constraint system tables InnoDB: Foreign key constraint system tables created InnoDB: Started mysqld: ready for connections 一个新的InnoDB数据库被创建了。你可以用**mysql**这样通常的MySQL客户端程序连接到MySQL服务器。当你用**mysqladmin shutdown**关闭MySQL服务器之时,输出类似如下: 010321 18:33:34  mysqld: Normal shutdown 010321 18:33:34  mysqld: Shutdown Complete InnoDB: Starting shutdown... InnoDB: Shutdown completed 你可以看数据文件和日志文件,并且你可以看见文件被创建。日志目录也包含一个名为ib_arch_log_0000000000的小文件。这个文件是数据库被创建的结果,数据库被创建之后InnoDB切断日志归档。当MySQL再次启动之时,数据文件&日志文件已经被创建,所以输出更简洁: InnoDB: Started mysqld: ready for connections 你可以添加innodb_file_per_table选项到my.cnf文件,并且让InnoDB存储每一个表到MySQL数据库目录里自己的.ibd文件。请参阅[15.2.6.6节,“使用Per-Table表空间”](# "15.2.6.6. Using Per-Table Tablespaces")。 #### 15.2.5.1. 处理InnoDB初始化问题 如果InnoDB在一个文件操作中打印一个操作系统错误,通常问题是如下中的一个: ·        你没有创建一个InnoDB数据文件目录或InnoDB日志目录。 ·        **mysqld**没有访问这些目录的权限以创建文件。 ·        **mysqld**不能恰当地读取my.cnf或my.ini选项文件,因此不能看到你指定的选项。 ·        磁盘已满,或者超出磁盘配额。 ·        你已经创建一个子目录,它的名字与你指定的数据文件相同。 ·        在innodb_data_home_dir或innodb_data_file_path有一个语法错误。 当InnoDB试着初始化它的表空间或日志文件之时,如果出错了,你应该删除InnoDB创建的所有文件。这意味着是所有ibdata文件和所有ib_logfiles文件。万一你创建了一些InnoDB表,为这些表也从MySQL数据库目录删除相应的.frm文件(如果你使用多重表空间的话,也删除任何.ibd文件)。然后你可以试着再次创建InnoDB数据库。最好是从命令提示符启动MySQL服务器,以便你可以查看发生了什么。 ### 15.2.6. 创建InnoDB表 [15.2.6.1. 如何在InnoDB用不同API来使用事务](#) [15.2.6.2. 转换MyISAM表到InnoDB](#) [15.2.6.3. AUTO_INCREMENT列如何在InnoDB中工作](#) [15.2.6.4.外键约束](#) [15.2.6.5. InnoDB和MySQL复制](#) [15.2.6.6. 使用Per-Table表空间](#) 假如你用mysql test命令启动MySQL客户端。要创建一个InnoDB表,你必须在表创建SQL语句中指定ENGINE = InnoDB或者TYPE = InnoDB选项: CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) ENGINE=InnoDB; CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) TYPE=InnoDB; SQL语句在表空间的列上创建一个表和索引,表空间包含你在my.cnf指定的数据文件。此外,MySQL在MySQL数据库目录下的test目录里创建一个名为customers.frm的文件。内部地,InnoDB为'test/customers'表往自己的数据目录添加一个条目。这意味这你可以在其它数据库创建一个具有相同名字customers的表,表的名字不会与InnoDB内的冲突。 你可以对任何InnoDB表,通过使用SHOW TABLE STATUS语句,查询在InnoDB表空间内空闲空间的数量。表空间内空闲空间的数量出现在SHOW TABLE STATUS的输出结果内的Comment节里。例如: SHOW TABLE STATUS FROM test LIKE 'customers' 注意,统计的SHOW只给出关于InnoDB表的大概情况。它们被用于SQL优化。可是,表和索引保留的大小,以字节为单位是准确的。 #### 15.2.6.1. 如何在InnoDB中用不同的API来使用事务 默认地,每个连接到MySQL服务器的客户端开始之时是允许自动提交模式的,这个模式自动提交你运行的每个SQL语句。要使用多语句事务,你可以用SQL语句SET AUTOCOMMIT = 0禁止自动提交,并且用COMMIT和ROLLBACK来提交或回滚你的事务。 如果你想要autocommit保持打开状态,可以在START TRANSACTION与COMMIT或ROLLBACK之间封装你的事务。下列的例子演示两个事务。第一个是被提交的,第二个是被回滚的: shell> mysql test Welcome to the MySQL monitor.  Commands end with ; or \g. Your MySQL connection id is 5 to server version: 3.23.50-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> CREATE TABLE CUSTOMER (A INT, B CHAR (20), INDEX (A))     -> ENGINE=InnoDB; Query OK, 0 rows affected (0.00 sec) mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO CUSTOMER VALUES (10, 'Heikki'); Query OK, 1 row affected (0.00 sec) mysql> COMMIT; Query OK, 0 rows affected (0.00 sec) mysql> SET AUTOCOMMIT=0; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO CUSTOMER VALUES (15, 'John'); Query OK, 1 row affected (0.00 sec) mysql> ROLLBACK; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM CUSTOMER; +------+--------+ | A    | B      | +------+--------+ |   10 | Heikki | +------+--------+ 1 row in set (0.00 sec) mysql> 在类似PHP, Perl DBI/DBD, JDBC, ODBC, 或者MySQL的标准C调用接口这样的API上,你能够以字符串形式发送事务控制语句,如COMMIT,到MySQL服务器,就像其它任何的SQL语句那样,诸如SELECT或INSERT。一些API也提供单独的专门的事务提交和回滚函数或者方法。 #### 15.2.6.2. 转换MyISAM表到InnoDB 要点:你不应该在mysql数据库(比如,user或者host)里把MySQL系统表转换为InnoDB类型。系统表总是MyISAM型。 如果你想要所有(非系统)表都被创建成InnoDB表,你可以简单地把default-table-type=innodb行添加到my.cnf或my.ini文件的[mysqld]节里。 InnoDB对MyISAM存储引擎采用的单独索引创建方法没有做专门的优化。因此,它不值得导出或导入表以及随后创建索引。改变一个表为InnoDB型最快的办法就是直接插入进一个InnoDB表。即,使用ALTER TABLE ... ENGINE=INNODB,或用相同的定义创建一个空InnoDB表,并且用INSERT INTO ... SELECT * FROM ...插入行。 如果你对第二个键有UNIQUE约