Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Limits Relating to Transaction Handling in NDB Cluster

25.2.7.3 NDB 集群中事务处理的限制

NDB 集群在事务处理方面存在一些限制。这些限制包括以下几点:

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

    未提交的数据永远不会被返回,但当一个事务修改多行同时与读取同一行的事务并发时,读取事务可能会观察到不同的行的“before”值、“after”值或两者,因为读取请求可以在其他事务提交之前或之后被处理。

    要确保某个事务只读取“before”值或“after”值,可以使用 SELECT ... LOCK IN SHARE MODE 来施加行锁。在这种情况下,锁将被持有直到拥有事务被提交。使用行锁也可能会导致以下问题:

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

    • 事务处理开销增加,因为读取需要提交阶段

    • 可能会耗尽可用的并发锁数量,该数量由 MaxNoOfConcurrentOperations 限定

    NDB 使用 READ COMMITTED 对所有读取操作,除非使用了 LOCK IN SHARE MODEFOR UPDATE 修饰符。LOCK IN SHARE MODE 导致共享行锁被使用;FOR UPDATE 导致独占行锁被使用。唯一键读取自动升级到独占锁以确保自洽读取;BLOB 读取也使用额外的锁以确保一致性。

    请参阅 第 25.6.8.4 节,“NDB 集群备份故障排除”,以了解 NDB 集群的事务隔离级别实现如何影响 NDB 数据库的备份和恢复。

  • 事务和 BLOB 或 TEXT 列。 NDBCLUSTER 只存储 MySQL 的 BLOBTEXT 数据类型的部分列值在 MySQL 可见的表中;剩余的 BLOBTEXT 列值被存储在一个内部表中,该表不可访问 MySQL。这引发了两个相关的问题,您应该在执行包含这些类型的列的表的 SELECT 语句时注意这些问题:

    1. 对于任何来自 NDB 集群表的 SELECT 语句:如果 SELECT 语句包括一个 BLOBTEXT 列,则 READ COMMITTED 事务隔离级别将被转换为带读锁的读取。这是为了保证一致性。

    2. 对于任何使用唯一键查找来检索任何使用 BLOBTEXT 数据类型的列的 SELECT 语句,并在事务中执行的,在事务期间将在表上持有共享读锁——即,直到事务被提交或回滚。

      这不适用于使用索引或表扫描的查询,即使是对具有 BLOBTEXT 列的 NDB 表。

      例如,考虑表 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 列。

      您可以通过避免使用唯一键查找来检索 BLOBTEXT 列,或者,在无法避免的情况下,尽快提交事务来帮助最小化共享读锁的问题。

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

    一种绕过可能阻塞读取的解决方法是强制 SQL 节点忽略唯一索引,而使用 IGNORE INDEX 索引提示作为 SELECT 语句的一部分(见 第 10.9.4 节,“索引提示”)。因为 MySQL 服务器为每个在 NDB 中创建的唯一索引创建了一个有序索引,这允许有序索引被读取,而避免了唯一索引访问锁定。结果读取与提交读取一致,返回读取时的最后提交值。

    通过有序索引读取使用集群中的资源较少,可能具有较高的延迟。

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

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

    这种行为不同于其他事务存储引擎,如InnoDB,它可能回滚单个语句。

  • 事务和内存使用情况。 如本章其他地方所提到的,NDB Cluster 不善于处理大事务;它更适合执行多个小事务,每个事务包含少量操作,而不是尝试执行一个大事务,包含许多操作。除其他考虑因素外,大事务需要非常大的内存量。因此,MySQL 语句的交易行为受到以下列表的影响:

    • TRUNCATE TABLENDB 表上不是事务性的。如果 TRUNCATE TABLE 无法清空表,则必须重新运行直到成功。

    • DELETE FROM(即使没有 WHERE 子句) 事务性的。对于包含许多行的表,您可能会发现,使用多个 DELETE FROM ... LIMIT ... 语句来“分块”删除操作可以提高性能。如果您的目标是清空表,则可能想使用 TRUNCATE TABLE instead。

    • LOAD DATA 语句。 LOAD DATANDB 表上不是事务性的。

      Important

      执行 LOAD DATA 语句时,NDB 引擎会在不规则的间隔提交事务,以便更好地利用通信网络。无法预先知道何时提交事务。

    • ALTER TABLE 和事务。 在将 NDB 表复制到 ALTER TABLE 中时,创建副本的操作不是事务性的。(无论如何,这个操作将在副本被删除时回滚。)

  • 事务和 COUNT() 函数。 使用 NDB Cluster 复制时,无法保证 COUNT() 函数在副本上的事务一致性。换言之,在源上执行一系列语句(INSERTDELETE 或两者)以在单个事务中更改表中的行数时,在副本上执行 SELECT COUNT(*) FROM table 查询可能会产生中间结果。这是因为 SELECT COUNT(...) 可能执行脏读,并不是 NDB 存储引擎的 bug。(参见 Bug #31321 以获取更多信息。)