首页 > 数据库 > > 14.8.1 InnoDB 表
参考官方文档:
https://dev.mysql.com/doc/refman/5.7/en/innodb-tables.html
14.8.1.1 创建InnoDB 表
要创建InnoDB表,请使用CREATE TABLE语句。
CREATE TABLE t1 (a INT, b CHAR (20), PRIMARY KEY (a)) ENGINE=InnoDB;
如果将InnoDB定义为默认存储引擎,则不需要指定ENGINE = InnoDB子句。 要检查默认存储引擎,请发出以下语句:
mysql> SELECT @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB |
+--------------------------+
如果您计划使用mysqldump或复制来重放默认存储引擎不是InnoDB的服务器上的CREATE TABLE语句,您仍然可以使用ENGINE = InnoDB子句。
InnoDB表及其索引可以在系统表空间,文件每表表空间或常规表空间中创建。 当innodb_file_per_table被启用(默认情况下)时,InnoDB表将隐式创建在单独的每个表的文件表空间中。 相反,当innodb_file_per_table被禁用时,在InnoDB系统表空间中隐式创建一个InnoDB表。 要在常规表空间中创建表,请使用CREATE TABLE ... TABLESPACE语法。
当您创建InnoDB表时,MySQL会在MySQL数据目录下的数据库目录中创建一个.frm文件。 有关.frm文件的更多信息,请参阅InnoDB表和.frm文件。 对于在每个表文件表空间中创建的表,MySQL默认在数据库目录中创建一个.ibd表空间文件。 InnoDB系统表空间中创建的表是在驻留在MySQL数据目录中的现有ibdata文件中创建的。 在常规表空间中创建的表是在现有的常规表空间.ibd文件中创建的。 一般的表空间文件可以在MySQL数据目录内部或外部创建。 有关更多信息,请参见第14.7.9节“InnoDB常规表空间”。
在内部,InnoDB为InnoDB数据字典添加了每个表的条目。 该条目包括数据库名称。 例如,如果在test数据库中创建表t1,则数据库名称的数据字典条目为'test/t1'。 这意味着您可以在不同的数据库中创建一个同名的表(t1),并且表名不会在InnoDB内部发生冲突。
InnoDB 表和 .frm文件
MySQL将数据字典信息存储在数据库目录中的.frm文件中。 与其他MySQL存储引擎不同,InnoDB还在系统表空间内部自己的内部数据字典中对表格信息进行编码。 当MySQL删除一个表或数据库时,会删除一个或多个.frm文件以及InnoDB数据字典中的相应条目。 不能在数据库之间移动InnoDB表仅通过移动.frm文件。
InnoDB 表和 Row 格式
InnoDB表的默认行格式由innodb_default_row_format配置选项定义,该选项的默认值为DYNAMIC。DYNAMIC和COMPRESSED的行格式允许您利用InnoDB的功能,如表压缩和长列值的高效离页存储。 要使用这些行格式,必须启用innodb_file_per_table(默认为MySQL 5.6.6),并且必须将innodb_file_format设置为 Barracuda。
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_file_format=barracuda;
CREATE TABLE t3 (a INT, b CHAR (20), PRIMARY KEY (a)) ROW_FORMAT=DYNAMIC;
CREATE TABLE t4 (a INT, b CHAR (20), PRIMARY KEY (a)) ROW_FORMAT=COMPRESSED;
或者,您可以使用CREATE TABLE ... TABLESPACE语法在常规表空间中创建InnoDB表。 常规表空间支持所有行格式。
CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1 ROW_FORMAT=DYNAMIC;
CREATE TABLE ... TABLESPACE语法也可用于在系统表空间中使用 Dynamic 行格式创建InnoDB表格,以及使用 Compact 或 Redundant 行格式的表。
CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE = innodb_system ROW_FORMAT=DYNAMIC;
InnoDB 表和主键
总是为InnoDB表定义一个主键,指定一列或多列:
例如,在包含关于人的信息的表中,不要在(名,姓)上创建主键,因为多个人可以具有相同的名称,有些人姓名为空白,有时人们更改他们的姓名。 有很多的约束条件,通常没有明显的一组列用作主键,所以您创建一个带有数字ID的新列作为主键的全部或一部分。 您可以声明自动增量列,以便在插入行时自动填充升序值:
# The value of ID can act like a pointer between related items in different tables. CREATE TABLE t5 (id INT AUTO_INCREMENT, b CHAR (20), PRIMARY KEY (id)); # The primary key can consist of more than one column. Any autoinc column must come first. CREATE TABLE t6 (id INT AUTO_INCREMENT, a INT, b CHAR (20), PRIMARY KEY (id,a));
虽然表在没有定义主键的情况下工作正常,但主键涉及许多性能方面,并且是任何大型或经常使用的表的关键设计方面。 建议您始终在CREATE TABLE语句中指定主键。 如果您创建表,加载数据,然后运行ALTER TABLE以稍后添加主键,则该操作比创建表时定义主键慢得多
查看InnoDB 表属性
要查看InnoDB表的属性,请发出SHOW TABLE STATUS语句:
mysql> SHOW TABLE STATUS FROM test LIKE 't%' \G;
InnoDB表格属性也可以使用InnoDB Information Schema系统表查询:
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test/t1' \G
14.8.1.2 一个InnoDB 表的物理行结构
InnoDB表的物理行结构取决于创建表时指定的行格式。 如果未指定行格式,则使用默认行格式。 InnoDB表的默认行格式由innodb_default_row_format配置选项定义,该选项的默认值为DYNAMIC。
确定InnoDB表的行格式
要确定InnoDB表的行格式,请使用SHOW TABLE STATUS。 例如:
mysql> SHOW TABLE STATUS IN test1\G
您还可以通过查询INFORMATION_SCHEMA.INNODB_SYS_TABLES来确定InnoDB表的行格式。
mysql> SELECT NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test1/t1';
+----------+------------+
| NAME | ROW_FORMAT |
+----------+------------+
| test1/t1 | Dynamic |
+----------+------------+
冗余行格式特征
REDUNDANT格式可以保留与旧版本MySQL的兼容性。
InnoDB表中使用REDUNDANT行格式的行具有以下特征:
COMPACT的行格式特征
与REDUNDANT格式相比,COMPACT行格式的行存储空间减少了大约20%,但代价是某些操作的CPU使用量增加。 如果您的工作负载是受缓存命中率和磁盘速度限制的典型负载,则COMPACT格式可能会更快。 如果工作负载是一个受CPU速度限制的罕见情况,则紧凑格式可能会变慢。
使用COMPACT行格式的InnoDB表中的行具有以下特征:
InnoDB不会截断VARCHAR列的尾部空格。
InnoDB为CHAR(N)保留至少N个字节。 在很多情况下保留最小空间N可以在不造成索引页碎片的情况下就地完成列更新。 相比之下,对于ROW_FORMAT = REDUNDANT,CHAR(N)列占用最大字符字节长度×N
InnoDB将长度大于或等于768字节的固定长度字段编码为可变长度字段,这些字段可以存储在页外。 例如,如果字符集的最大字节长度大于3,CHAR(255)列可能会超过768个字节,与utf8mb4一样。
ROW_FORMAT = DYNAMIC和ROW_FORMAT = COMPRESSED处理CHAR存储的方式与ROW_FORMAT = COMPACT相同。
DYNAMIC 和 COMPRESSED 行格式特征
DYNAMIC和COMPRESSED行格式是COMPACT行格式的变体。
14.8.1.3 移动或拷贝 InnoDB 表
本节介绍将部分或全部InnoDB表移动或复制到不同服务器或实例的技术。 例如,您可能将整个MySQL实例移动到更大,更快的服务器; 您可能会将整个MySQL实例克隆到新的复制从服务器; 您可以将单个表复制到另一个实例以开发和测试应用程序,或者复制到数据仓库服务器以生成报告。
在Windows上,InnoDB始终以小写内部存储数据库和表名。 要将数据库以二进制格式从Unix移动到Windows或从Windows移动到Unix,请使用小写名称创建所有数据库和表。 完成此操作的一种便捷方法是在创建任何数据库或表之前,将以下行添加到my.cnf或my.ini文件的[mysqld]部分中:
[mysqld] lower_case_table_names=1
可传输表空间
可移动表空间功能使用FLUSH TABLES ... FOR EXPORT来准备InnoDB表,以便从一个服务器实例复制到另一个服务器实例。 要使用此功能,InnoDB表必须使用设置为ON的innodb_file_per_table创建,以便每个InnoDB表都有其自己的表空间。
拷贝数据文件(冷备份方式)
InnoDB数据和日志文件在具有相同浮点数格式的所有平台上都是二进制兼容的。 如果浮点格式不同,但您的表中没有使用FLOAT或DOUBLE数据类型,则过程相同:只需复制相关文件即可。
在移动或复制文件 - 每表.ibd文件时,数据库目录名称在源系统和目标系统上必须相同。 存储在InnoDB共享表空间中的表定义包含数据库名称。 存储在表空间文件中的事务ID和日志序列号在数据库之间也不同。
要将.ibd文件和关联的表从一个数据库移动到另一个数据库,请使用RENAME TABLE语句:
RENAME TABLE db1.tbl_name TO db2.tbl_name;
如果你有一个.ibd文件的“干净的”备份,你可以将它恢复到源自它的MySQL安装,如下所示:
1.自从您复制.ibd文件以来,该表格一定不能被删除或截断,因为这样做会更改存储在表空间内的表格ID。
2. ALTER TABLE tbl_name DISCARD TABLESPACE;
3.将备份.ibd文件复制到适当的数据库目录。
4.发出这个ALTER TABLE语句来告诉InnoDB为表使用新的.ibd文件:
ALTER TABLE tbl_name IMPORT TABLESPACE;
注意:
ALTER TABLE ... IMPORT TABLESPACE功能不强制导入数据的外键约束。
在这种情况下,“clean”.ibd文件备份是满足以下要求的文件:
您可以使用以下方法创建干净的备份.ibd文件:
1.停止来自mysqld服务器的所有活动并提交所有事务。
2.等到SHOW ENGINE INNODB STATUS显示数据库中没有活动事务,并且InnoDB的主线程状态为等待服务器活动。 然后,您可以制作.ibd文件的副本。
另一种制作.ibd文件的干净副本的方法是使用MySQL企业备份产品:
1.使用MySQL企业备份来备份InnoDB安装。
2.在备份上启动第二个mysqld服务器,并让它清理备份中的.ibd文件。
导出和导入(mysqldump)
您可以使用mysqldump将您的表转储到一台机器上,然后将转储文件导入到另一台机器上。 使用这种方法,无论格式是否不同或表中是否包含浮点数据都无关紧要。
提高此方法性能的一种方法是在导入数据时关闭自动提交模式,假定表空间具有足够的空间用于导入事务生成的大回滚段。 仅在导入整个表格或表格的一部分后执行提交。
14.8.1.4 将表格从MyISAM转换到InnoDB
如果您希望将MyISAM表格转换为InnoDB以获得更好的可靠性和可扩展性,请在转换之前查看以下指南和技巧。
调整MyISAM和InnoDB的内存使用情况
在从MyISAM表转换出来时,降低key_buffer_size配置选项的值以释放不再需要的内存以缓存结果。 增加innodb_buffer_pool_size配置选项的值,该选项执行为InnoDB表分配缓存内存的类似角色。 InnoDB缓冲池同时缓存表数据和索引数据,加快查询查询速度并将查询结果保存在内存中以供重用。
在繁忙的服务器上,运行关闭查询缓存的基准测试。 InnoDB缓冲池提供了类似的好处,所以查询缓存可能会不必要地占用内存。
处理太长或太短的事务
由于MyISAM表不支持事务处理,因此您可能没有太注意自动提交配置选项以及COMMIT和ROLLBACK语句。 这些关键字对于允许多个会话同时读取和写入InnoDB表很重要,可在写入繁重的工作负载中提供可观的可伸缩性优势。
在事务处于打开状态时,系统将在事务开始时保留数据快照,如果系统在杂散事务继续运行时插入,更新和删除数百万行,则会导致大量开销。 因此,请注意避免长时间运行的事务:
上述技巧可以节省在过长的事务中浪费的内存和磁盘空间。 当事务是更短的事务时,问题是过量的I/O。 通过每个COMMIT,MySQL确保每次更改都安全地记录到磁盘上,这涉及到一些I/O。
处理死锁
您可能会在MySQL错误日志中看到引用“死锁”的警告消息或SHOW ENGINE INNODB STATUS的输出。 尽管名字可怕,死锁并不是InnoDB表的严重问题,并且通常不需要任何纠正措施。 当两个事务开始修改多个表时,以不同顺序访问表时,他们可以达到每个事务正在等待另一个事务并且都不能继续的状态。 当启用死锁检测时(默认),MySQL立即检测到这种情况并取消(回滚)“较小”的事务,从而允许另一个进行。 如果使用innodb_deadlock_detect配置选项禁用死锁检测,InnoDB将依靠innodb_lock_wait_timeout设置来回滚发生死锁的事务。
无论哪种方式,您的应用程序都需要错误处理逻辑来重新启动由于死锁而被强制取消的事务。 当您重新发布与之前相同的SQL语句时,原始计时问题不再适用。 另一个事务已经完成并且您可以继续,或者其他事务仍在进行中,事务等待其完成。
如果经常发生死锁警告,您可以查看应用程序代码以一致的方式对SQL操作进行重新排序,或者缩短事务处理时间。 您可以使用启用的innodb_print_all_deadlocks选项进行测试,以查看MySQL错误日志中的所有死锁警告,而不仅仅是SHOW ENGINE INNODB STATUS输出中的最后一个警告。
转换 一个存在的表
要将非InnoDB表转换为使用InnoDB,请使用ALTER TABLE:
ALTER TABLE table_name ENGINE=InnoDB;
重要
不要将MySQL数据库中的MySQL系统表从MyISAM转换为InnoDB类型。 这是一个不受支持的操作, 类型。
传输现存的数据
要将大量数据传输到如上节所示创建的空InnoDB表中,请使用INSERT INTO innodb_table SELECT * FROM myisam_table ORDER BY primary_key_columns插入行。
插入数据后,您还可以为InnoDB表创建索引。 从历史上看,创建新的二级索引对于InnoDB来说是一个缓慢的操作,但是现在您可以在索引创建步骤中以相对较少的开销加载数据之后创建索引。
如果您在二级键具有UNIQUE约束,则可以通过在导入操作过程中暂时关闭唯一性检查来加速表导入:
SET unique_checks=0;
... import operation ...
SET unique_checks=1;
对于大型表,这可以节省磁盘I / O,因为InnoDB可以使用其更改缓冲区将二级索引记录作为批次写入。 确保数据不包含重复的密钥。 unique_checks允许但不要求存储引擎忽略重复密钥。
为了更好地控制插入过程,您可以分片插入大表:
INSERT INTO newtable SELECT * FROM oldtable WHERE yourkey > something AND yourkey <= somethingelse;
插入所有记录后,可以重命名表格。
在大表转换过程中,增加InnoDB缓冲池的大小以减少磁盘I/O,最大为物理内存的80%。 您还可以增加InnoDB日志文件的大小。
为每个表定义主键
PRIMARY KEY子句是影响MySQL查询性能和表和索引空间使用情况的关键因素。 主键唯一标识表中的一行。 表中的每一行都必须具有主键值,并且没有两行可以具有相同的主键值。
这些是主键的准则,其次是更详细的解释。
考虑将主键添加到任何尚未拥有主键的表中。 根据表格的最大投影尺寸使用最小的实际数字类型。 这可以使每一行稍微更紧凑,这可以为大型表节省大量的空间。 如果表具有任何二级索引,则空间节省将成倍增加,因为主键值在每个二级索引条目中都会重复。 除了减少磁盘上的数据大小外,小型主键还可以让更多数据适合缓冲池,加快各种操作并提高并发性。
如果表在一些较长的列(如VARCHAR)上已经有一个主键,请考虑添加一个新的无符号AUTO_INCREMENT列并将主键切换为该键,即使该列未在查询中引用也是如此。 这种设计更改可以在二级索引中节省大量空间。 您可以将以前的主键列指定为UNIQUE NOT NULL以强制执行与PRIMARY KEY子句相同的约束,即防止所有这些列出现重复值或空值。
如果您将相关信息分布在多个表中,则通常每个表使用相同的列作为其主键。 例如,人事数据库可能有多个表,每个表都有一个员工编号的主键。 销售数据库可能包含一些带有客户编号主键的表,以及其他具有订单编号主键的表。 由于使用主键的查找速度非常快,因此可以为这些表构造高效的连接查询。
如果您完全不使用PRIMARY KEY子句,MySQL会为您创建一个不可见的子句。 这是一个6字节的值,可能比您需要的时间更长,从而浪费空间。 因为它是隐藏的,所以你不能在查询中引用它。
14.8.1.5 在InnoDB中的 AUTO_INCREMENT 处理
InnoDB AUTO_INCREMENT 锁模式
本节介绍用于生成自动增量值的AUTO_INCREMENT锁定模式的行为以及每种锁定模式如何影响复制。 自动增量锁定模式在启动时使用innodb_autoinc_lock_mode配置参数进行配置。
以下术语用于描述innodb_autoinc_lock_mode设置:
可以预先确定要插入的行数的语句(最初处理语句时)。 这包括没有嵌套子查询的单行和多行INSERT和REPLACE语句,但不包括INSERT ... ON DUPLICATE KEY UPDATE。
预先不知道要插入的行数(以及所需自动增量值的数量)的语句。 这包括INSERT ... SELECT,REPLACE ... SELECT和LOAD DATA语句,但不是普通的INSERT。 InnoDB会在处理每行时为AUTO_INCREMENT列一次分配一个新值。
这些是“简单插入”语句,用于为新行的某些(但不是全部)行指定自动递增值。 下面是一个例子,其中c1是表t1的AUTO_INCREMENT列:
INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
另一种类型的“混合模式插入”是INSERT ... ON DUPLICATE KEY UPDATE,它在最坏的情况下实际上是一个INSERT,后跟一个UPDATE,其中AUTO_INCREMENT列的分配值可能会或可能不会被用于 更新阶段。
innodb_autoinc_lock_mode配置参数有三种可能的设置。 对于“ traditional”,“ consecutive”或“ interleaved”锁定模式,设置分别为0,1或2。
传统的锁定模式提供了与在MySQL 5.1中引入innodb_autoinc_lock_mode配置参数之前相同的行为。 传统的锁定模式选项提供了向后兼容性,性能测试和解决“混合模式插入”的问题,这是由于语义的可能差异。
在这种锁定模式下,所有“INSERT-like”语句都会获得一个特殊的表级AUTO-INC锁定,用于插入带有AUTO_INCREMENT列的表中。 此锁通常保持在语句的末尾(而不是事务结束),以确保为给定的INSERT语句序列以可预测和可重复的顺序分配自动递增值,并确保自动递增 由任何给定语句分配的值是连续的。
在基于语句的复制的情况下,这意味着在从属服务器上复制SQL语句时,自动增量列使用与主服务器上相同的值。 执行多条INSERT语句的结果是确定性的,从属设备重现与主设备上相同的数据。 如果由多个INSERT语句生成的自增量值被交错,则两个并发INSERT语句的结果将是不确定的,并且不能可靠地使用基于语句的复制传播到从服务器。
为了清楚说明,请考虑使用此表的示例:
CREATE TABLE t1 ( c1 INT(11) NOT NULL AUTO_INCREMENT, c2 VARCHAR(10) DEFAULT NULL, PRIMARY KEY (c1) ) ENGINE=InnoDB;
假设有两个事务正在运行,每个事务都将行插入带有AUTO_INCREMENT列的表中。 一个事务使用插入1000行的INSERT ... SELECT语句,另一个事务使用插入一行的简单INSERT语句:
Tx1: INSERT INTO t1 (c2) SELECT 1000 rows from another table ... Tx2: INSERT INTO t1 (c2) VALUES ('xxx');
InnoDB无法预先告知在Tx1的INSERT语句中SELECT从SELECT中检索了多少行,并且随着语句的进行一次一个地分配自动递增值。 通过在表达式末尾保持表级锁定,每次只能执行一次引用表t1的INSERT语句,并且不会交错由不同语句生成的自动递增数字。 由Tx1 INSERT ... SELECT语句生成的自动递增值是连续的,并且由Tx2中的INSERT语句使用的(单个)自动递增值要么小于要么大于用于Tx1的所有那些值,具体取决于哪个 语句首先执行。
只要从二进制日志(使用基于语句的复制或恢复场景中)重播时SQL语句以相同顺序执行,结果与之前运行Tx1和Tx2时的结果相同。 因此,直到语句结束时,表级锁才会使INSERT语句使用自动增量安全的用于基于语句的复制。 但是,当多个事务同时执行插入语句时,这些表级锁会限制并发性和可伸缩性。
在前面的示例中,如果没有表级锁定,则用于Tx2中INSERT的自动增量列的值取决于执行语句的时间。 如果Tx2的INSERT在Tx1的INSERT运行时(而不是在它开始之前或完成之后)执行,则由两个INSERT语句分配的特定自动递增值是非确定性的,并且可能因运行而存在差异。
在连续锁定模式下,InnoDB可以避免对预先知道行数的“ simple insert”语句使用表级AUTO-INC锁定,并且仍然保留基于语句的复制的确定性执行和安全性。
如果您没有使用二进制日志重放SQL语句作为恢复或复制的一部分,则可以使用交叉锁定模式来消除所有使用表级AUTO-INC锁定以获得更高的并发性和性能,但代价是允许 由语句分配的自动增量编号中存在间隙。
这是默认的锁定模式。 在这种模式下,“ bulk inserts”使用特殊的AUTO-INC表级锁定,直到语句结束。 这适用于所有INSERT ... SELECT,REPLACE ... SELECT和LOAD DATA语句。 每次只能执行一条保持AUTO-INC锁定的语句。 如果大容量插入操作的源表与目标表不同,则在从源表中选择的第一行执行共享锁后,将采用目标表上的AUTO-INC锁。 如果批量插入操作的源和目标是同一个表,则在对所有选定行进行共享锁定后,将执行AUTO-INC锁定。
“简单插入”(预先知道要插入的行数)通过在互斥锁(轻量级锁)控制下获取所需数量的自动递增值来避免表级AUTO-INC锁定, 这只在分配过程中持续,直到语句完成。 除非另一个事务持有AUTO-INC锁定,否则不使用表级AUTO-INC锁定。 如果另一个事务持有AUTO-INC锁定,则“简单插入”将等待AUTO-INC锁定,就像它是“批量插入”一样。
这种锁定模式可确保在出现行数未知的INSERT语句的情况下(以及在语句进行时自动递增数字的位置),所有由“INSERT-like”指定的自动递增值 语句是连续的,并且操作对于基于语句的复制是安全的。
简而言之,这种锁定模式显着提高了可扩展性,同时可以安全地使用基于语句的复制。 此外,与“ traditional”锁定模式一样,任何给定语句分配的自动递增数字都是连续的。 对于任何使用自动增量的语句,与“ traditional”模式相比,语义没有变化,但有一个重要的例外。
“混合模式插入”例外,其中用户为多行“简单插入”中的某些(但不是全部)行提供AUTO_INCREMENT列的显式值。 对于这样的插入,InnoDB分配比要插入的行数更多的自动增量值。 但是,自动分配的所有值都会连续生成(并因此高于)最近执行的前一个语句生成的自动递增值。 “ Excess”号码丢失。
在这种锁定模式下,没有“INSERT-like”语句使用表级AUTO-INC锁定,并且可以同时执行多个语句。这是最快和最可伸缩的锁定模式,但当从二进制日志中重播SQL语句时,使用基于语句的复制或恢复方案时,这种方式并不安全。
在此锁定模式下,自动递增值保证在所有同时执行的“INSERT-like”语句中是唯一且单调递增的。但是,由于多个语句可能同时生成数字(也就是说,数字的分配是跨越语句交错的),所以为任何给定语句插入的行生成的值可能不连续。
如果执行的唯一语句是提前知道要插入的行数的“简单插入”,则除了“混合模式插入”外,对于单个语句生成的数字没有间隔。但是,执行“批量插入”时,可能会有由任何给定语句分配的自动递增值中的间隙。
InnoDB AUTO_INCREMENT锁模式使用意义
如果您使用基于语句的复制,请将innodb_autoinc_lock_mode设置为0或1,并在主服务器及其从服务器上使用相同的值。 如果您使用innodb_autoinc_lock_mode = 2(“interleaved”)或者主设备和从设备不使用相同的锁定模式的配置,则自动递增值在从设备上不能保证与主设备上的相同。
如果您使用的是基于行或混合格式的复制,则所有自动增量锁定模式都是安全的,因为基于行的复制对SQL语句的执行顺序不敏感。
在所有锁定模式(0,1和2)中,如果生成自动递增值的事务回退,那些自动递增值将“丢失”。 一旦为自动增量列生成值,无论是否完成“INSERT-like”语句以及是否回滚包含的事务,都无法回滚该值。 这些丢失的值不会被重复使用。 因此,表的AUTO_INCREMENT列中存储的值可能存在间隙。
在所有锁定模式(0,1和2)中,如果您为AUTO_INCREMENT列指定负值,则不会定义自动递增机制的行为。
在所有锁定模式(0,1和2)中,如果值大于可以存储在指定整数类型中的最大整数,则自动递增机制的行为未定义。
将innodb_autoinc_lock_mode设置为0(“传统”)或1(“连续”)时,由任何给定语句生成的自动增量值是连续的,没有间隙,因为表级AUTO-INC锁定一直保持到语句结束,并且一次只能执行一个这样的语句。
将innodb_autoinc_lock_mode设置为2(“交错”)时,由“批量插入”生成的自动递增值中可能存在间隙,但前提是同时执行“INSERT-like”语句。
对于锁定模式1或2,连续的语句之间可能会出现间隙,因为对于批量插入,每个语句所需的自动递增值的确切数量可能不知道,并且可能会高估。
考虑一个“混合模式插入”,其中“简单插入”指定一些(但不是全部)结果行的自动增量值。 例如,假设c1是表t1的AUTO_INCREMENT列,并且最近自动生成的序列号是100。
mysql> CREATE TABLE t1 (
-> c1 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> c2 CHAR(1)
-> )
ENGINE = INNODB;
现在,考虑下面的“混合模式插入”语句:
mysql> INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
当innodb_autoinc_lock_mode设置为0时(“传统”),四个新行是:
mysql> SELECT c1, c2 FROM t1 ORDER BY c2;
+-----+------+
| c1 | c2 |
+-----+------+
| 1 | a |
| 101
| b |
| 5 | c |
| 102 | d |
+-----+------+
下一个可用自动递增值为103,因为自动递增值一次分配一次,而不是在语句执行开始时一次全部分配。 无论是否同时执行“INSERT-like”语句(任何类型),此结果为真。
当innodb_autoinc_lock_mode设置为1时(“连续”),这四个新行也是:
mysql> SELECT c1, c2 FROM t1 ORDER BY c2;
+-----+------+
| c1 | c2 |
+-----+------+
| 1 | a |
| 101 | b |
| 5 | c |
| 102 | d |
+-----+------+
但是,在这种情况下,下一个可用自动递增值是105,而不是103,因为在处理语句时分配了四个自动递增值,但只使用了两个。 无论是否同时执行“INSERT-like”语句(任何类型),此结果为真。
将innodb_autoinc_lock_mode设置为模式2(“交错”)时,四个新行是:
mysql> SELECT c1, c2 FROM t1 ORDER BY c2;
+-----+------+
| c1 | c2 |
+-----+------+
| 1 | a |
| x | b |
| 5 | c |
| y | d |
+-----+------+
x和y的值是唯一的,并且大于以前生成的任何行。 但是,x和y的具体值取决于由并发执行的语句生成的自动增量值的数量。
最后,考虑当最近生成的序列号为100时发布的以下语句:
mysql> INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (101,'c'), (NULL,'d');
对于任何innodb_autoinc_lock_mode设置,此语句会生成一个重复键错误23000(Can't write; duplicate key in table),因为101分配给该行(NULL,'b')并插入行(101,'c' )失败。
在所有锁定模式(0,1和2)中,在INSERT语句序列中间修改AUTO_INCREMENT列值可能导致“ Duplicate entry”错误。 例如,如果您执行的UPDATE操作将AUTO_INCREMENT列值更改为大于当前最大自动递增值的值,则未指定未使用的自动递增值的后续INSERT操作可能会遇到“ Duplicate entry”错误。 以下示例演示了此行为。
mysql> CREATE TABLE t1 (
-> c1 INT NOT NULL AUTO_INCREMENT,
-> PRIMARY KEY (c1) -> )ENGINE = InnoDB;
mysql> INSERT INTO t1 VALUES(0), (0), (3);
mysql> SELECT c1 FROM t1;
+----+
| c1 |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> UPDATE t1 SET c1 = 4 WHERE c1 = 1;
mysql> SELECT c1 FROM t1;
+----+
| c1 |
+----+
| 2 |
| 3 |
| 4 |
+----+
mysql> INSERT INTO t1 VALUES(0); ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY'
InnoDB AUTO_INCREMENT计数器初始化
如果您为InnoDB表指定AUTO_INCREMENT列,InnoDB数据字典中的表句柄将包含一个称为自动递增计数器的特殊计数器,该计数器用于为该列分配新值。 该计数器仅存储在主存储器中,而不是存储在磁盘上。
要在服务器重新启动后初始化自动增量计数器,InnoDB在第一次插入包含AUTO_INCREMENT列的表中执行以下语句的等效操作。
SELECT MAX(ai_col) FROM table_name FOR UPDATE;
InnoDB增加语句检索到的值并将其分配给表中的列和自动递增计数器。 默认情况下,该值增加1.此默认值可以由auto_increment_increment配置设置覆盖。
如果表为空,则InnoDB将使用值1.此默认值可以由auto_increment_offset配置设置覆盖。
如果SHOW TABLE STATUS语句在自动递增计数器初始化之前检查该表,InnoDB将初始化但不会递增该值。 该值被存储以供稍后插入使用。 此初始化在表上使用正常的独占锁定读取,锁持续到事务结束。 InnoDB按照相同的步骤初始化新创建的表的自动增量计数器。
在自动递增计数器初始化之后,如果您没有明确指定AUTO_INCREMENT列的值,InnoDB会递增计数器并将新值赋给列。 如果插入明确指定列值的行,并且该值大于当前计数器值,则将计数器设置为指定的列值。
只要服务器运行,InnoDB就会使用内存自动增量计数器。 如上所述,当服务器停止并重新启动时,InnoDB将第一个INSERT的每个表的计数器重新初始化为表,如前所述。
服务器重启也会取消CREATE TABLE和ALTER TABLE语句中的AUTO_INCREMENT = N表选项的效果,您可以使用这些语句与InnoDB表一起使用来设置初始计数器值或更改当前计数器值。
14.8.1.6 InnoDB 和外键约束
外键定义
InnoDB表的外键定义受以下条件限制:
引用行为
InnoDB表的外键引用操作受以下条件限制:
外键使用和错误信息
您可以通过查询INFORMATION_SCHEMA.KEY_COLUMN_USAGE表获得有关外键及其用法的一般信息,并且还可以在INFORMATION_SCHEMA数据库中的INNODB_SYS_FOREIGN和INNODB_SYS_FOREIGN_COLS表中找到更多特定于InnoDB表的信息。
除了SHOW ERRORS之外,如果涉及InnoDB表的外键错误(通常是MySQL Server中的错误150),您可以通过检查SHOW ENGINE INNODB STATUS的输出来获得最新InnoDB外键错误的详细解释。
14.8.1.7 InnoDB 表的限制
警告:
不要将MySQL数据库中的MySQL系统表从MyISAM转换为InnoDB表。 这是一个不受支持的操作。 如果这样做,MySQL将不会重新启动,直到您从备份中还原旧系统表或通过重新初始化数据目录重新生成它们(请参见第2.10.1节“初始化数据目录”)。
最大数量和最小数量
innodb_large_prefix已弃用,并将在未来版本中删除。 Innodb_large_prefix是在MySQL 5.5中引入的,用于禁用大型索引键前缀,以便与不支持大型索引键前缀的早期InnoDB版本兼容。
对于使用REDUNDANT或COMPACT行格式的InnoDB表,索引键前缀长度限制为767字节。 例如,假设utf8mb3字符集和每个字符的最大长度为3个字节,则您可能会在TEXT或VARCHAR列上的列前缀索引超过255个字符时触发此限制。
尝试使用超过限制的索引键前缀长度将返回错误。 为避免复制配置中出现此类错误,请避免在主服务器上也启用innodb_large_prefix,如果slave上也不能启用的话。
ERROR 1070 (42000): Too many key parts specified; max 16 parts allowed
如果一行的长度小于页的一半,则所有行都存储在本地页面中。 如果它超过页的一半,则可以选择可变长度的列用于外部页外存储,直到该行适合半页内为止。
mysql> CREATE TABLE t (a VARCHAR(8000), b VARCHAR(10000), -> c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000), -> f VARCHAR(10000), g VARCHAR(10000)) ENGINE=InnoDB; ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
最小的表空间大小略大于10MB。 最大的表空间大小取决于InnoDB页面大小。

最大表空间大小也是表的最大大小。
Barracuda文件格式中的ROW_FORMAT = COMPRESSED假定页面大小最多为16KB,并使用14位指针。
支持32KB和64KB页面大小,但对于大于16KB的页面大小,不支持ROW_FORMAT = COMPRESSED。 对于32KB和64KB页面大小,最大记录大小为16KB。 对于innodb_page_size = 32k,范围大小为2MB。 对于innodb_page_size = 64k,扩展区大小为4MB。
使用特定InnoDB页面大小的MySQL实例不能使用来自使用不同页面大小的实例的数据文件或日志文件。
InnoDB表的限制
如第14.6.12.1节“配置持久性优化器统计参数”中所述,您可以通过打开innodb_stats_persistent配置选项使ANALYZE TABLE收集的统计信息更加精确和更稳定。 启用该设置后,重要的是在索引列数据发生重大更改后运行ANALYZE TABLE,因为不会定期重新计算统计信息(例如服务器重新启动后)。
如果启用持久性统计信息设置,则可以通过修改innodb_stats_persistent_sample_pages系统变量来更改随机dives次数。 如果持久统计设置已禁用,请修改innodb_stats_transient_sample_pages系统变量。
MySQL在连接优化中使用索引基数估计。 如果连接未以正确的方式进行优化,请尝试使用ANALYZE TABLE。 在少数情况下,ANALYZE TABLE并不能为您的特定表生成足够好的值,您可以在查询中使用FORCE INDEX来强制使用特定索引,或设置max_seeks_for_key系统变量以确保MySQL优先于表的索引查找扫描。 参见第B.5.5节“与优化器相关的问题”。
在MySQL 5.7.18之前,InnoDB通过扫描聚集索引来处理SELECT COUNT(*)语句。 从MySQL 5.7.18开始,InnoDB通过遍历最小的可用二级索引来处理SELECT COUNT(*)语句,除非索引或优化器提示指示优化器使用不同的索引。 如果二级索引不存在,则会扫描聚簇索引。
如果索引记录不完全在缓冲池中,处理SELECT COUNT(*)语句需要一些时间。 为了加快计数,您可以创建一个计数器表并让应用程序根据插入操作对其进行更新并删除它。 但是,在数千个并发事务正在启动对同一个计数器表的更新的情况下,此方法可能无法很好地扩展。 如果大致的行数足够,可以使用SHOW TABLE STATUS。
InnoDB以相同的方式处理SELECT COUNT(*)和SELECT COUNT(1)操作。 没有性能差异。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3130669/ ,如需转载,请注明出处,否则将追究法律责任。