ITPub博客

首页 > 数据库 > > 14.8.1 InnoDB 表

14.8.1 InnoDB 表

作者:飘絮絮絮丶 时间:2020-05-12 09:58:56 0 删除 编辑

参考官方文档:
dev.mysql.com/doc/refma



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行格式的行具有以下特征:


  • 每个索引记录包含一个6字节的头。头用于链接连续的记录,也用于行级锁定。
  • 聚集索引中的记录包含所有用户定义列的字段。另外,还有一个6字节的事务ID字段和一个7字节的滚动指针字段。
  • 如果没有为表定义主键,则每个聚簇索引记录还包含一个6字节的行ID字段。
  • 每个二级索引记录还包含为聚簇索引键定义的所有不在二级索引中的主键字段。
  • 记录包含指向记录每个字段的指针。如果记录中字段的总长度小于128字节,则指针是一个字节;否则,两个字节。这些指针的数组称为记录目录。这些指针指向的区域称为记录的数据部分。
  • 在内部,InnoDB以固定长度格式存储固定长度的字符列,例如CHAR(10)。 InnoDB不会截断VARCHAR列的尾随空格。
  • InnoDB将长度大于或等于768字节的固定长度字段编码为可变长度字段,这些字段可以存储在页外。例如,如果字符集的最大字节长度大于3,CHAR(255)列可能会超过768个字节,与utf8mb4一样。
  • SQL NULL值在记录目录中保留一个或两个字节。除此之外,如果存储在可变长度列中,则SQL NULL值在记录的数据部分保留零字节。在固定长度的列中,它在记录的数据部分中保留列的固定长度。为NULL值保留固定空间使得能够将列从NULL更新为非NULL值,而不导致索引页的碎片化。



COMPACT的行格式特征


与REDUNDANT格式相比,COMPACT行格式的行存储空间减少了大约20%,但代价是某些操作的CPU使用量增加。 如果您的工作负载是受缓存命中率和磁盘速度限制的典型负载,则COMPACT格式可能会更快。 如果工作负载是一个受CPU速度限制的罕见情况,则紧凑格式可能会变慢。


使用COMPACT行格式的InnoDB表中的行具有以下特征:


  • 每个索引记录包含一个5字节的标题,其前面可以有一个可变长度的头。 头用于链接连续的记录,也用于行级锁定。
  • 记录头的可变长度部分包含一个用于指示NULL列的位向量。 如果索引中可以为NULL的列数为N,则该位向量占用CEILING(N / 8)个字节。 (例如,如果有9到16列的任何地方可以为NULL,则位向量使用两个字节。)NULL的列不占用除此向量中位之外的空间。头的可变长度部分也包含可变长度列的长度。 每个长度需要一个或两个字节,具体取决于列的最大长度。 如果索引中的所有列都不是NULL并且具有固定长度,则记录标头不包含可变长度部分。


  • 对于每个non-NULL变长字段,记录头包含一个或两个字节中列的长度。 只有部分列存储在溢出页面的外部或最大长度超过255个字节且实际长度超过127个字节时才需要两个字节。 对于外部存储的列,2字节长度表示内部存储部分的长度加上指向外部存储部分的20字节指针。 内部部分是768字节,所以长度是768 + 20。 20字节的指针存储列的真实长度。
  • 记录头后面是非NULL列的数据内容。
  • 聚集索引中的记录包含所有用户定义列的字段。 另外,还有一个6字节的事务ID字段和一个7字节的滚动指针字段。
  • 如果没有为表定义主键,则每个聚簇索引记录还包含一个6字节的行ID字段。
  • 每个二级索引记录还包含为聚簇索引键定义的所有不在二级索引中的主键字段。 如果这些主键字段中的任何一个是可变长度,则每个二级索引的记录标题都有一个可变长度部分来记录它们的长度,即使二级索引是在固定长度列上定义的。
  • 在内部,对于不可变长度的字符集,InnoDB以固定长度格式存储固定长度的字符列,例如CHAR(10)。



InnoDB不会截断VARCHAR列的尾部空格。

  • 在内部,对于可变长度字符集(如utf8mb3和utf8mb4),InnoDB通过修剪尾部空格尝试将CHAR(N)存储为N个字节。 如果CHAR(N)列值的字节长度超过N个字节,则InnoDB会将尾随空格修剪为列值字节长度的最小值。 CHAR(N)列的最大长度是最大字符字节长度×N



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文件中没有未交付的事务修改。
  • .ibd文件中没有未合并的插入缓冲区条目。
  • 清除已从.ibd文件中删除所有删除标记的索引记录。
  • mysqld已将.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表很重要,可在写入繁重的工作负载中提供可观的可伸缩性优势。


在事务处于打开状态时,系统将在事务开始时保留数据快照,如果系统在杂散事务继续运行时插入,更新和删除数百万行,则会导致大量开销。 因此,请注意避免长时间运行的事务:

  • 如果您正在使用mysql会话进行交互式实验,请在完成后始终执行COMMIT(最终确定更改)或ROLLBACK(撤消更改)。 关闭交互式会话,而不是让它们长时间保持打开状态,以避免意外长时间保持打开事务。


  • 确保应用程序中的任何错误处理程序还有ROLLBACK未完成的更改或COMMIT完成这些更改。


  • ROLLBACK是一个相对昂贵的操作,因为INSERT,UPDATE和DELETE操作在COMMIT之前写入到InnoDB表中,期望大多数更改成功提交并且回滚很少。 在试验大量数据时,避免对大量行进行更改,和回滚这些更改。
  • 当使用一系列INSERT语句加载大量数据时,请定期commit结果以避免持续数小时的事务。 在数据仓库的典型加载操作中,如果出现问题,可以截断表(使用TRUNCATE TABLE)并从头开始,而不是执行ROLLBACK。



上述技巧可以节省在过长的事务中浪费的内存和磁盘空间。 当事务是更短的事务时,问题是过量的I/O。 通过每个COMMIT,MySQL确保每次更改都安全地记录到磁盘上,这涉及到一些I/O。

  • 对于InnoDB表上的大多数操作,应该使用设置autocommit = 0。 从效率角度来看,当您发出大量连续的INSERT,UPDATE或DELETE语句时,可以避免不必要的I / O。 从安全角度来看,如果您在mysql命令行或应用程序中的异常处理程序中犯了错误,则允许您发出ROLLBACK语句来恢复丢失或乱码的数据。
  • autocommit = 1适用于InnoDB表是运行一系列查询以生成报告或分析统计信息的时候。 在这种情况下,没有与COMMIT或ROLLBACK相关的I / O惩罚,InnoDB可以自动优化只读工作负载。
  • 如果您进行了一系列相关更改,则最后使用单个COMMIT一次性完成所有更改。 例如,如果您将相关的信息插入到多个表中,请在完成所有更改后执行一次COMMIT。 或者,如果您运行了许多连续的INSERT语句,则在加载所有数据后执行一次COMMIT; 如果您正在执行数百万条INSERT语句,可能会通过每10,000或100,000条记录发出一个COMMIT来分割巨大的事务,因此事务不会变得太大。
  • 请记住,即使是SELECT语句也会打开一个事务,因此在交互式mysql会话中运行一些报告或调试查询后,发出COMMIT或关闭mysql会话。



处理死锁


您可能会在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查询性能和表和索引空间使用情况的关键因素。 主键唯一标识表中的一行。 表中的每一行都必须具有主键值,并且没有两行可以具有相同的主键值。


这些是主键的准则,其次是更详细的解释。

  • 为每个表声明一个PRIMARY KEY。 通常,查找单行时,它是WHERE子句中引用的最重要的列。
  • 在原始CREATE TABLE语句中声明PRIMARY KEY子句,而不是稍后通过ALTER TABLE语句添加它。
  • 仔细选择列及其数据类型。尽量使用数字列而不是字符串的字符列
  • 如果没有一个稳定的,唯一的,非空的数字列,请考虑使用自动增量列。
  • 如果怀疑主键列的值是否可以更改,那么自动增加列也是一个不错的选择。 更改主键列的值是一项昂贵的操作,可能涉及在表中和每个二级索引内重新排列数据。





考虑将主键添加到任何尚未拥有主键的表中。 根据表格的最大投影尺寸使用最小的实际数字类型。 这可以使每一行稍微更紧凑,这可以为大型表节省大量的空间。 如果表具有任何二级索引,则空间节省将成倍增加,因为主键值在每个二级索引条目中都会重复。 除了减少磁盘上的数据大小外,小型主键还可以让更多数据适合缓冲池,加快各种操作并提高并发性。



如果表在一些较长的列(如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-like” 语句

    所有在表中生成新行的语句,包括INSERT,INSERT ... SELECT,REPLACE,REPLACE ... SELECT和LOAD DATA。 包括“简单插入”,“批量插入”和“混合模式”插入。

  • “Simple inserts”



可以预先确定要插入的行数的语句(最初处理语句时)。 这包括没有嵌套子查询的单行和多行INSERT和REPLACE语句,但不包括INSERT ... ON DUPLICATE KEY UPDATE。

  • “Bulk inserts”

预先不知道要插入的行数(以及所需自动增量值的数量)的语句。 这包括INSERT ... SELECT,REPLACE ... SELECT和LOAD DATA语句,但不是普通的INSERT。 InnoDB会在处理每行时为AUTO_INCREMENT列一次分配一个新值。

  • “Mixed-mode inserts”

这些是“简单插入”语句,用于为新行的某些(但不是全部)行指定自动递增值。 下面是一个例子,其中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。


  • innodb_autoinc_lock_mode = 0(“传统”锁定模式)



传统的锁定模式提供了与在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锁定以获得更高的并发性和性能,但代价是允许 由语句分配的自动增量编号中存在间隙。

  • innodb_autoinc_lock_mode = 1 (“consecutive”lock mode)



这是默认的锁定模式。 在这种模式下,“ 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”号码丢失。

  • innodb_autoinc_lock_mode = 2(“交错”锁定模式)



在这种锁定模式下,没有“INSERT-like”语句使用表级AUTO-INC锁定,并且可以同时执行多个语句。这是最快和最可伸缩的锁定模式,但当从二进制日志中重播SQL语句时,使用基于语句的复制或恢复方案时,这种方式并不安全。


在此锁定模式下,自动递增值保证在所有同时执行的“INSERT-like”语句中是唯一且单调递增的。但是,由于多个语句可能同时生成数字(也就是说,数字的分配是跨越语句交错的),所以为任何给定语句插入的行生成的值可能不连续。


如果执行的唯一语句是提前知道要插入的行数的“简单插入”,则除了“混合模式插入”外,对于单个语句生成的数字没有间隔。但是,执行“批量插入”时,可能会有由任何给定语句分配的自动递增值中的间隙。



InnoDB AUTO_INCREMENT锁模式使用意义

  • 在复制时使用自动增量



如果您使用基于语句的复制,请将innodb_autoinc_lock_mode设置为0或1,并在主服务器及其从服务器上使用相同的值。 如果您使用innodb_autoinc_lock_mode = 2(“interleaved”)或者主设备和从设备不使用相同的锁定模式的配置,则自动递增值在从设备上不能保证与主设备上的相同。


如果您使用的是基于行或混合格式的复制,则所有自动增量锁定模式都是安全的,因为基于行的复制对SQL语句的执行顺序不敏感。

  • “Lost”自动递增值和序列间隙



在所有锁定模式(0,1和2)中,如果生成自动递增值的事务回退,那些自动递增值将“丢失”。 一旦为自动增量列生成值,无论是否完成“INSERT-like”语句以及是否回滚包含的事务,都无法回滚该值。 这些丢失的值不会被重复使用。 因此,表的AUTO_INCREMENT列中存储的值可能存在间隙。

  • 为AUTO_INCREMENT列指定一个负值

在所有锁定模式(0,1和2)中,如果您为AUTO_INCREMENT列指定负值,则不会定义自动递增机制的行为。

  • 如果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' )失败。

  • 在一系列INSERT语句的中间修改AUTO_INCREMENT列值



在所有锁定模式(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允许外键引用任何索引列或一组列。 但是,在被引用的表中,必须有一个索引,其中被引用的列按照相同顺序列为第一列。
  • InnoDB目前不支持具有用户定义分区的表的外键。 这意味着没有用户分区的InnoDB表可能包含外键引用或外键引用的列。
  • InnoDB允许外键约束引用非唯一键。 这是对标准SQL的InnoDB扩展。




引用行为


InnoDB表的外键引用操作受以下条件限制:


  • 尽管MySQL服务器允许SET DEFAULT,但InnoDB将其视为无效。 InnoDB表不允许使用CREATE TABLE和ALTER TABLE语句



  • 如果父表中有多行具有相同的引用键值,则InnoDB在外键检查中起作用,就好像具有相同键值的其他父行不存在一样。 例如,如果你定义了一个RESTRICT类型约束,并且有一个包含多个父行的子行,InnoDB不允许删除任何这些父行。
  • InnoDB根据与外键约束对应的索引中的记录,通过深度优先算法执行级联操作。


  • 如果ON UPDATE CASCADE或ON UPDATE SET NULL递归更新它先前在级联期间更新过的同一个表,它就像RESTRICT一样。 这意味着您不能使用自引用ON UPDATE CASCADE或ON UPDATE SET NULL操作。 这是为了防止级联更新导致的无限循环。 另一方面,可以使用自引用ON DELETE SET NULL,就像自引用ON DELETE CASCADE一样。 级联操作的嵌套深度不能超过15层。


  • 一般来说,在插入,删除或更新许多行的SQL语句中,InnoDB逐行检查UNIQUE和FOREIGN KEY约束。 在执行外键检查时,InnoDB在它必须查看的子或父记录上设置共享的行级锁。 InnoDB立即检查外键约束; 该检查不会延迟到事务提交。 根据SQL标准,默认行为应该是延迟检查。 也就是说,只有在处理完整个SQL语句后才能检查约束。 在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节“初始化数据目录”)。


最大数量和最小数量


  • 一个表最多可以包含1017列(在MySQL 5.6.9中从前面的限制1000提高)。 虚拟生成的列包含在此限制中。
  • 一个表最多可以包含64个二级索引。
  • 如果启用innodb_large_prefix(默认值),则对于使用DYNAMIC或COMPRESSED行格式的InnoDB表,索引键前缀限制为3072个字节。 如果innodb_large_prefix被禁用,则任何行格式的表的索引键前缀限制为767字节。


innodb_large_prefix已弃用,并将在未来版本中删除。 Innodb_large_prefix是在MySQL 5.5中引入的,用于禁用大型索引键前缀,以便与不支持大型索引键前缀的早期InnoDB版本兼容。
对于使用REDUNDANT或COMPACT行格式的InnoDB表,索引键前缀长度限制为767字节。 例如,假设utf8mb3字符集和每个字符的最大长度为3个字节,则您可能会在TEXT或VARCHAR列上的列前缀索引超过255个字符时触发此限制。
尝试使用超过限制的索引键前缀长度将返回错误。 为避免复制配置中出现此类错误,请避免在主服务器上也启用innodb_large_prefix,如果slave上也不能启用的话。

  • 如果通过在创建MySQL实例时指定innodb_page_size选项将InnoDB页面大小减小为8KB或4KB,则根据16KB页面大小的3072字节的限制,索引键的最大长度将按比例降低。 也就是说,当页面大小为8KB时,最大索引关键字长度为1536字节,当页面大小为4KB时,最大索引关键字长度为768字节。
  • 多列索引最多允许16列。 超出限制会返回错误。



ERROR 1070 (42000): Too many key parts specified; max 16 parts allowed

  • 对于4KB,8KB,16KB和32KB页面大小,除可变长度列(VARBINARY,VARCHAR,BLOB和TEXT)外,最大行长度略小于页面的一半。 例如,16KB的默认innodb_page_size的最大行长度大约为8000字节。 对于64KB的InnoDB页面大小,最大行长度大约为16000字节。 LONGBLOB和LONGTEXT列必须小于4GB,并且总行长度(包括BLOB和TEXT列)必须小于4GB。



如果一行的长度小于页的一半,则所有行都存储在本地页面中。 如果它超过页的一半,则可以选择可变长度的列用于外部页外存储,直到该行适合半页内为止。

  • 尽管InnoDB内部支持大于65,535字节的行大小,但MySQL本身对所有列的总大小施加了65,535行大小限制:



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

  • 在一些较旧的操作系统上,文件必须小于2GB。 这不是InnoDB本身的限制,但是如果你需要一个大的表空间,使用几个较小的数据文件而不是一个大的数据文件来配置它。


  • InnoDB日志文件的大小可以达到512GB。


最小的表空间大小略大于10MB。 最大的表空间大小取决于InnoDB页面大小。







最大表空间大小也是表的最大大小。


  • InnoDB中的默认页面大小为16KB。 您可以通过在创建MySQL实例时配置innodb_page_size选项来增加或减少页面大小。





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表的限制


  • analyze table 通过对每个索引树执行随机潜水并相应地更新索引基数估计来确定索引基数(如SHOW INDEX输出的基数列中所示)。 由于这些只是估算值,重复运行的ANALYZE TABLE可能会产生不同的数字。 这会使InnoDB表上的ANALYZE TABLE快速,但不是100%准确,因为它并不考虑所有行。



如第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节“与优化器相关的问题”。

  • 如果语句或事务在表上运行,并且ANALYZE TABLE在同一个表上运行,然后再运行第二个ANALYZE TABLE操作,则第二个ANALYZE TABLE操作将被阻塞,直到语句或事务完成。 出现此问题的原因是ANALYZE TABLE在ANALYZE TABLE完成运行时将当前已加载的表定义标记为已过时。 新的语句或事务(包括第二个ANALYZE TABLE语句)必须将新的表定义加载到表缓存中,直到当前正在运行的语句或事务完成并清除旧的表定义时才能发生。 加载多个并发表定义不受支持。
  • 除了表保留的物理大小外,SHOW TABLE STATUS不会在InnoDB表上提供精确的统计信息。 行数只是SQL优化器中使用的粗略估计。
  • InnoDB不保留表的内部行数,因为并发事务可能同时“看到”不同数量的行。 因此,SELECT COUNT(*)语句仅计算当前事务可见的行



在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)操作。 没有性能差异。

  • 在Windows上,InnoDB始终以小写内部存储数据库和表名。 要将数据库以二进制格式从Unix移动到Windows或从Windows移动到Unix,请使用小写名称创建所有数据库和表。
  • AUTO_INCREMENT列ai_col必须定义为索引的一部分,以便可以在表上执行索引SELECT MAX(ai_col)查找的等效操作以获取最大列值。 通常,这是通过将列设置为某个表索引的第一列来实现的。
  • InnoDB在与AUTO_INCREMENT列关联的索引的末尾设置独占锁,同时初始化表中先前指定的AUTO_INCREMENT列。

    在innodb_autoinc_lock_mode = 0的情况下,InnoDB使用特殊的AUTO-INC表锁定模式,其中获取锁并在访问自动增量计数器时将其保存到当前SQL语句的末尾。 当AUTO-INC表锁定被保持时,其他客户端不能插入到表中。 innodb_autoinc_lock_mode = 1的“批量插入”会发生同样的情况。 innodb_autoinc_lock_mode = 2时不使用表级AUTO-INC锁定。
  • 当您重新启动MySQL服务器时,InnoDB可能会重用为AUTO_INCREMENT列生成但从未存储的旧值(即在回滚的旧事务期间生成的值)。
  • 当AUTO_INCREMENT integer列中的值超出时,后续的INSERT操作将返回重复键错误。 这是一般的MySQL行为。
  • DELETE FROM tbl_name不会重新生成表,而是会逐个删除所有行。
  • 级联外键操作不会激活触发器。
  • 您不能创建列名称与InnoDB内部列名称(包括DB_ROW_ID,DB_TRX_ID,DB_ROLL_PTR和DB_MIX_ID)匹配的表。 此限制适用于在任何字母大小写中使用名称。

    mysql> CREATE TABLE t1 (c1 INT, db_row_id INT) ENGINE=INNODB; ERROR 1166 (42000): Incorrect column name 'db_row_id'



    锁和事务


    如果innodb_table_locks = 1(缺省值),LOCK TABLES在每个表上获取两个锁。 除了MySQL层的表锁之外,它还获得了InnoDB表锁。 4.1.2之前版本的MySQL没有获得InnoDB表锁; 旧行为可以通过设置innodb_table_locks = 0来选择。 如果没有获取InnoDB表锁,即使表中的某些记录被其他事务锁定,LOCK TABLES也会完成。



    在MySQL 5.7中,innodb_table_locks = 0对使用LOCK TABLES ... WRITE显式锁定的表没有影响。 它确实对表锁定以供LOCK TABLES ... WRITE隐式(例如,通过触发器)或LOCK TABLES ... READ读取或写入。


  • 事务持有的所有InnoDB锁都在事务提交或中止时释放。 因此,在autocommit= 1模式下在InnoDB表上调用LOCK TAB没有什么意义,因为所获取的InnoDB表将会立即释放。
  • 您不能在事务中间锁定其他表,因为LOCK TABLES执行隐式COMMIT和UNLOCK TABLES。
  • 数据修改事务的限制是产生undo记录的96 * 1023个并发事务。 将128个回滚段中的32个分配给用于修改临时表和相关对象的事务的非重做日志。 这可以将并发数据修改事务的最大数量从128K减少到96K。 96K限制假定事务不修改临时表。 如果所有数据修改事务也修改临时表,则限制为32K个并发事务。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3130669/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-09-09

  • 博文量
    2646
  • 访问量
    42190