NDB群集中与事务处理相关的限制
NDB Cluster在事务处理方面存在许多限制。其中包括:
事务隔离级别。该
NDBCLUSTER
存储引擎只支持READ COMMITTED
事务隔离级别。(InnoDB
,例如,支持READ COMMITTED
,READ UNCOMMITTED
,REPEATABLE READ
,和SERIALIZABLE
。)你应该记住,NDB
器具READ COMMITTED
在每行的基础;当读取请求到达存储该行的数据节点时,返回的是该行当时的最后提交版本。未提交的数据永远不会返回,但是当修改多个行的事务与读取相同行的事务同时提交时,执行读取操作的事务可以观察其中的不同行的“ before ”值,“ after ”值或两者。,这是因为可以在提交另一个事务之前或之后处理给定的行读取请求。
为确保给定的事务仅读取值之前或之后,可以使用施加行锁
SELECT ... LOCK IN SHARE MODE
。在这种情况下,锁定将一直保持到拥有事务提交为止。使用行锁也会导致以下问题:- 锁定等待超时错误的频率增加,并发减少
- 由于读取需要提交阶段,因此增加了事务处理开销
- 耗尽可用并发锁数的可能性受到以下限制:
MaxNoOfConcurrentOperations
NDB
用途READ COMMITTED
对于所有除非改性剂,例如读取,LOCK IN SHARE MODE
或FOR UPDATE
使用。LOCK IN SHARE MODE
导致使用共享的行锁;FOR UPDATE
导致使用排他的行锁。唯一键读取会自动更新其锁,NDB
以确保读取前后一致。BLOB
读取还使用额外的锁定来保持一致性。有关NDB Cluster的事务隔离级别的实现如何影响数据库的备份和还原的信息,请参见“ NDB Cluster备份故障排除”
NDB
。事务和BLOB或TEXT列。
NDBCLUSTER
仅存储使用MySQL 可见表中的任何MySQLBLOB
或TEXT
数据类型的列值的一部分;BLOB
或的其余部分TEXT
存储在MySQL无法访问的单独的内部表中。这引起了两个相关的问题,每当SELECT
在包含这些类型的列的表上执行语句时,您都应该意识到这些问题:- 对于
SELECT
NDB群集表中的任何表:如果SELECT
包括aBLOB
或TEXT
列,则READ COMMITTED
事务隔离级别将转换为具有读取锁定的读取。这样做是为了保证一致性。 对于
SELECT
使用唯一键查找来检索使用任何BLOB
或TEXT
数据类型并且在事务内执行的任何列的任何事物,在事务期间(即直到事务进行之前),共享的读取锁将保留在表上。被提交或中止。使用索引或表扫描的查询不会发生此问题,即使对于
NDB
具有BLOB
或TEXT
列的表也是如此。例如,考虑
t
以下CREATE TABLE
语句定义的表:CREATE TABLE t ( a INT NOT NULLAUTO_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 tWHERE c = 1;但是,此处显示的四个查询都不会导致共享读取锁定:
SELECT *FROM tWHERE b = 1;SELECT *FROM tWHERE d = '1';SELECT *FROM t;SELECT b,cWHERE a = 1;这是因为在这四个查询中,第一个使用索引扫描,第二个和第三个使用表扫描,而第四个在使用主键查找时,不检索any
BLOB
或TEXT
column 的值。通过避免使用检索
BLOB
或TEXT
列的唯一键查找的查询,或者在无法避免此类查询的情况下,通过尽早提交事务,可以帮助最大程度地减少共享读取锁的问题。
- 对于
唯一的键查找和事务隔离。唯一索引是
NDB
通过使用内部维护的隐藏索引表实现的。当NDB
使用唯一索引访问用户创建的表时,首先将读取隐藏的索引表以找到主键,然后使用该主键读取用户创建的表。为了避免在此双读操作期间修改索引,在隐藏索引表中找到的行将被锁定。当用户创建的唯一索引引用的行NDB
如果更新表,隐藏索引表将受到执行更新的事务的排他锁。这意味着对同一张(用户创建的)NDB
表的任何读取操作都必须等待更新完成。即使读取操作的事务级别为,也是如此READ COMMITTED
。可以用来绕过潜在的阻塞读取的一种解决方法是,强制SQL节点在执行读取时忽略唯一索引。这可以通过将
IGNORE INDEX
索引提示用作SELECT
读取表的语句的一部分来完成(请参见“索引提示”)。由于MySQL服务器会为中创建的每个唯一索引创建一个阴影排序索引NDB
,因此可以读取该排序索引,并避免了唯一索引访问锁定。结果读取与主键提交的读取保持一致,并在读取行时返回最后的提交值。通过有序索引进行读取会使群集中的资源使用效率降低,并且可能会有更高的延迟。
通过查询范围而不是唯一值,还可以避免使用唯一索引进行访问。
回滚。没有部分事务,也没有部分事务回滚。重复的密钥或类似错误会导致整个事务回滚。
此行为不同于其他事务存储引擎的行为,例如
InnoDB
可能回滚单个语句的行为。事务和内存使用情况。如本章其他地方所述,NDB群集不能很好地处理大型事务。与尝试包含多个操作的单个大型事务相比,执行多个具有少量操作的小型事务要好。除其他考虑因素外,大型事务需要非常大量的内存。因此,如下列表中所述,许多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群集复制时,无法保证
COUNT()
从服务器上功能的事务一致性。换句话说,在主服务器上执行更改单个事务中表中的行数的一系列语句(INSERT
,DELETE
或两者)时,在从服务器上执行查询可能会产生中间结果。这是由于可能执行脏读,而不是存储引擎中的错误。(有关更多信息,请参见Bug#31321。)SELECT COUNT(*)FROM table
SELECT COUNT(...)
NDB