文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  与 NDB Cluster 中事务处理相关的限制

25.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 MODEFOR UPDATE 等修饰符。 LOCK IN SHARE MODE 会导致使用共享行锁;FOR UPDATE 会导致使用独占行锁。唯一键读取会由 NDB 自动将它们的锁升级,以确保自一致性读取;BLOB 读取也会使用额外的锁定以确保一致性。

    请参见 第 25.6.8.4 节,“NDB Cluster 备份故障排除”,了解有关 NDB Cluster 事务隔离级别实现如何影响 NDB 数据库备份和还原的信息。

  • 交易和 BLOB 或 TEXT 列。  NDBCLUSTER 仅存储 MySQL 可见表中使用 MySQL 的任何 BLOBTEXT 数据类型的列值的某一部分;其余 BLOBTEXT 存储在另一个内部表中,该表对 MySQL 不可访问。这会导致两个相关的问题,您在执行 SELECT 语句时应注意这些问题,这些语句针对包含这些类型列的表:

    1. 对于从 NDB Cluster 表中进行的任何 SELECT:如果 SELECT 包含 BLOBTEXT 列,则 READ COMMITTED 事务隔离级别将转换为带有读锁的读取。这样做是为了保证一致性。

    2. 对于任何使用唯一键查找检索任何使用任何 BLOBTEXT 数据类型的列的 SELECT,并且该 SELECT 在交易中执行,在整个交易期间(即,直到交易提交或中止)将对表保持一个共享读锁。

      对于使用索引或表扫描的查询,即使针对包含 BLOBTEXT 列的 NDB 表,也不会出现此问题。

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

      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 表中由唯一索引引用的行被更新时,隐藏索引表会受到执行更新的交易的独占锁影响。这意味着对同一(用户创建的)NDB 表的任何读取操作都必须等待更新完成。即使读取操作的事务级别为 READ COMMITTED,也是如此。

    可以用来绕过可能阻塞读取的一种变通方法是强制 SQL 节点在执行读取时忽略唯一索引。这可以通过在读取表的 SELECT 语句中使用 IGNORE INDEX 索引提示来实现(请参见 第 10.9.4 节,“索引提示”)。由于 MySQL 服务器为在 NDB 中创建的每个唯一索引创建了一个影子排序索引,因此这可以让排序索引被读取,并避免唯一索引访问锁定。由此产生的读取与通过主键提交的读取一样一致,在读取行时返回最后一个提交的值。

    通过排序索引读取会对集群中的资源利用率较低,并且延迟可能更高。

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

  • 回滚。  不存在部分交易,也不存在交易的部分回滚。重复键或类似错误会导致整个交易回滚。

    这种行为与其他事务性存储引擎(如 InnoDB)的行为不同,后者可能会回滚单个语句。

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

    • TRUNCATE TABLE 在用于 NDB 表时不是事务性的。如果 TRUNCATE TABLE 无法清空表,则必须重新运行它,直到成功。

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

    • LOAD DATA 语句。  LOAD DATA 在用于 NDB 表时不是事务性的。

      重要

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

    • ALTER TABLE 和交易。  当复制 NDB 表作为 ALTER TABLE 的一部分时,复制的创建是非事务性的。(在任何情况下,当复制被删除时,此操作都会回滚。)

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