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

21.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 的事务隔离级别的实现如何影响数据库的备份和恢复的信息, 请参阅第 21.6.8.4 节,“NDB Cluster 备份故障排除”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,或者在无法避免此类查询的情况下,尽快提交事务。

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

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

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

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

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

    此行为不同于其他事务性存储引擎的行为,例如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,副本的创建是非事务性的。(无论如何,删除副本时都会回滚此操作。)

  • Transactions and the COUNT() function.  When using NDB Cluster Replication, it is not possible to guarantee the transactional consistency of the COUNT() function on the replica. In other words, when performing on the source a series of statements (INSERT, DELETE, or both) that changes the number of rows in a table within a single transaction, executing SELECT COUNT(*) FROM table queries on the replica may yield intermediate results. This is due to the fact that SELECT COUNT(...) may perform dirty reads, and is not a bug in the NDB storage engine. (See Bug #31321 for more information.)