Documentation Home
MySQL 8.0 参考手册  / 第 23 章 MySQL NDB Cluster 8.0  / 23.2 NDB Cluster 概述  / 23.2.7 NDB Cluster 的已知限制  /  18.2.7.3 与 NDB Cluster 中事务处理相关的限制

18.2.7.3 与 NDB Cluster 中事务处理相关的限制

NDB Cluster 在处理事务方面存在许多限制。其中包括:

  • 事务隔离级别。  NDBCLUSTER存储引擎只支持 事务READ COMMITTED隔离级别。(InnoDB例如,支持 READ COMMITTEDREAD UNCOMMITTEDREPEATABLE READSERIALIZABLE。)您应该记住,在每行的基础上NDB实施 ;READ COMMITTED当读取请求到达存储该行的数据节点时,返回的是该行当时最后提交的版本。

    永远不会返回未提交的数据,但是当修改多行的事务与读取相同行的事务同时提交时,执行读取的事务可以观察这些数据中不同行的之前 值、之后值或两者,因为给定的行读取请求可以在其他事务提交之前或之后处理。

    为确保给定的事务只在值之前或之后读取,您可以使用 SELECT ... LOCK IN SHARE MODE. 在这种情况下,锁会一直持有,直到拥有的事务被提交。使用行锁还会导致以下问题:

    • 锁等待超时错误的频率增加,并发性降低

    • 由于读取需要提交阶段而增加了事务处理开销

    • 可用并发锁数量耗尽的可能性,受限于 MaxNoOfConcurrentOperations

    NDB除非使用READ COMMITTED诸如 LOCK IN SHARE MODE或之类的修饰符,否则用于所有读取FOR UPDATELOCK IN SHARE MODE导致使用共享行锁; FOR UPDATE导致使用独占行锁。唯一键读取的锁会自动升级,NDB以确保读取自洽;BLOB读取还使用额外的锁定来保持一致性。

    有关NDB Cluster 的事务隔离级别的实现如何影响数据库的备份和恢复的信息, 请参阅第 18.6.8.4 节,“NDB Cluster 备份故障排除”NDB

  • 唯一键查找和事务隔离。  唯一索引是NDB 使用内部维护的隐藏索引表实现的。当NDB使用唯一索引访问用户创建的表时,首先读取隐藏索引表以找到主键,然后使用该主键读取用户创建的表。为了避免在这个双读操作期间修改索引,在隐藏索引表中找到的行被锁定。当用户创建的唯一索引引用的行NDB 表被更新时,隐藏索引表受到执行更新的事务的独占锁。这意味着对同一个(用户创建的)NDB表的任何读取操作都必须等待更新完成。即使读取操作的事务级别为 READ COMMITTED.

    一种可用于绕过潜在阻塞读取的解决方法是强制 SQL 节点在执行读取时忽略唯一索引。这可以通过使用IGNORE INDEX索引提示作为SELECT读取表的语句的一部分来完成(请参阅第 8.9.3 节,“索引提示”)。因为 MySQL 服务器为在中创建的每个唯一索引创建了一个阴影有序索引NDB,所以这让有序索引被读取,并避免了唯一索引访问锁定。生成的读取与主键的提交读取一样一致,返回读取行时的最后提交值。

    通过有序索引读取会降低集群中资源的使用效率,并且可能会有更高的延迟。

    也可以通过查询范围而不是唯一值来避免使用唯一索引进行访问。

  • 事务和 BLOB 或 TEXT 列。  NDBCLUSTER仅存储使用任何 MySQL BLOBTEXT表中对 MySQL 可见的数据类型的列值的一部分;BLOBor 的其余部分 TEXT存储在 MySQL 无法访问的单独内部表中。SELECT这会产生两个相关问题,每当对包含这些类型的列的表 执行语句时,您都应该注意这两个问题 :

    1. 对于SELECT来自 NDB Cluster 表的任何内容:如果 SELECT包含 BLOBor TEXT列,则 READ COMMITTED 事务隔离级别将转换为带读锁的读取。这样做是为了保证一致性。

    2. 对于任何SELECT使用唯一键查找来检索任何使用BLOBTEXT数据类型的任何列并且在事务中执行的任何事务,共享读锁会在事务持续期间保持在表上——也就是说,直到事务已提交或已中止。

      NDB对于使用索引或表扫描的查询,即使针对具有 BLOBTEXT列的 表 ,也不会发生此问题 。

      例如,考虑t 由以下CREATE TABLE语句定义的表:

      CREATE TABLE t (
          a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
          b INT NOT NULL,
          c INT NOT NULL,
          d TEXT,
          INDEX i(b),
          UNIQUE KEY u(c)
      ) ENGINE = NDB,

      以下查询t导致共享读锁,因为它使用唯一键查找:

      SELECT * FROM t WHERE c = 1;

      然而,这里显示的四个查询都没有导致共享读锁:

      SELECT * FROM t WHERE b = 1;
      
      SELECT * FROM t WHERE d = '1';
      
      SELECT * FROM t;
      
      SELECT b,c WHERE a = 1;

      这是因为,在这四个查询中,第一个使用索引扫描,第二个和第三个使用表扫描,第四个在使用主键查找时不检索任何 BLOBTEXT列的值。

      BLOB您可以通过避免使用检索或 列 的唯一键查找的查询来帮助最大程度地减少共享读取锁的问题TEXT,或者在无法避免此类查询的情况下,尽快提交事务。

  • 回滚。  没有部分事务,也没有事务的部分回滚。重复键或类似错误会导致整个事务回滚。

    此行为不同于其他事务性存储引擎的行为,例如InnoDB 可能会回滚单个语句。

  • 事务和内存使用。  如本章其他地方所述,NDB Cluster 不能很好地处理大型事务;最好执行多个小事务,每个小事务只包含几个操作,而不是尝试包含大量操作的单个大事务。在其他考虑因素中,大型事务需要非常大量的内存。因此,许多 MySQL 语句的事务行为受到影响,如下表所述:

    • TRUNCATE TABLENDB在表上使用时不是事务性的 。如果 a TRUNCATE TABLE清空表失败,则必须重新运行,直到成功。

    • DELETE FROM(即使没有 WHERE条款) 交易性的。对于包含大量行的表,您可能会发现通过使用多个DELETE FROM ... LIMIT ... 语句来“分删除操作可以提高性能。如果您的目标是清空表,那么您可能希望使用TRUNCATE TABLE

    • 加载数据语句。  在表 LOAD DATA上使用时不是事务性的 。NDB

      重要的

      执行LOAD DATA语句时, NDB引擎会以不规则的时间间隔执行提交,以便更好地利用通信网络。无法提前知道此类提交何时发生。

    • ALTER TABLE 和事务。  复制NDB表作为 的一部分时ALTER TABLE,副本的创建是非事务性的。(无论如何,删除副本时都会回滚此操作。)

  • 事务和 COUNT() 函数。  使用 NDB Cluster Replication 时,无法保证 COUNT()副本上函数的事务一致性。换句话说,当在源上执行一系列语句(INSERTDELETE或两者)更改单个事务中表中的行数时,在副本上执行查询可能会产生中间结果。这是由于可能会执行脏读,而不是 存储引擎中的错误。(有关更多信息,请参阅错误 #31321。) SELECT COUNT(*) FROM tableSELECT COUNT(...)NDB