NDB 叢集在處理交易方面存在一些限制。這些限制包括以下內容:
交易隔離等級。
NDBCLUSTER
儲存引擎僅支援READ COMMITTED
交易隔離等級。(例如,InnoDB
支援READ COMMITTED
、READ UNCOMMITTED
、REPEATABLE READ
和SERIALIZABLE
。)您應該記住,NDB
以逐列為基礎實作READ COMMITTED
;當讀取請求到達儲存該列的資料節點時,傳回的是當時該列最後提交的版本。永遠不會傳回未提交的資料,但是當修改多列的交易與讀取相同列的交易同時提交時,執行讀取的交易可能會觀察到這些列的不同列的「之前」值、「之後」值或兩者,原因是給定列的讀取請求可能在另一個交易提交之前或之後處理。
為了確保給定的交易僅讀取之前或之後的值,您可以使用
SELECT ... LOCK IN SHARE MODE
來強制執行列鎖定。在這種情況下,鎖定會一直保留到擁有該鎖定的交易提交為止。使用列鎖定也可能導致以下問題:鎖定等待逾時錯誤的頻率增加,並降低並行性
由於讀取需要提交階段,因此交易處理負擔增加
可能會耗盡可用的並行鎖定數量,該數量受
MaxNoOfConcurrentOperations
限制
NDB
對所有讀取使用READ COMMITTED
,除非使用諸如LOCK IN SHARE MODE
或FOR UPDATE
之類的修飾詞。LOCK IN SHARE MODE
會導致使用共用列鎖定;FOR UPDATE
會導致使用獨佔列鎖定。唯一索引鍵讀取的鎖定會由NDB
自動升級,以確保自我一致的讀取;BLOB
讀取也會為了保持一致性而採用額外的鎖定。請參閱 第 25.6.8.4 節,「NDB 叢集備份疑難排解」,以瞭解 NDB 叢集實作交易隔離等級如何影響
NDB
資料庫的備份和還原。交易與 BLOB 或 TEXT 資料行。
NDBCLUSTER
僅將使用任何 MySQL 的BLOB
或TEXT
資料類型的資料行值的其中一部分儲存在 MySQL 可見的資料表中;其餘的BLOB
或TEXT
則儲存在單獨的內部資料表中,MySQL 無法存取該資料表。這會產生兩個相關問題,當您在包含這些類型的資料行的資料表上執行SELECT
陳述式時,您應注意這些問題:對於任何來自 NDB 叢集資料表的
SELECT
:如果SELECT
包含BLOB
或TEXT
資料行,則READ COMMITTED
交易隔離等級會轉換為具有讀取鎖定的讀取。這樣做是為了保證一致性。對於任何使用唯一索引鍵查詢來擷取使用任何
BLOB
或TEXT
資料類型的任何資料行,並在交易中執行的SELECT
,在交易期間(即直到交易提交或中止為止)會對該資料表保留共用的讀取鎖定。使用索引或資料表掃描的查詢不會發生此問題,即使是針對具有
BLOB
或TEXT
資料行的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;
這是因為在這四個查詢中,第一個使用索引掃描,第二個和第三個使用資料表掃描,而第四個雖然使用主索引鍵查詢,但不會擷取任何
BLOB
或TEXT
資料行的值。您可以透過避免使用唯一索引鍵查詢來擷取
BLOB
或TEXT
資料行,或在無法避免此類查詢的情況下,盡快提交交易,以協助將共用讀取鎖定的問題降到最低。
唯一索引鍵查詢與交易隔離。唯一索引是在
NDB
中使用內部維護的隱藏索引資料表實作的。當使用唯一索引存取使用者建立的NDB
資料表時,首先會讀取隱藏的索引資料表,以尋找隨後用於讀取使用者建立的資料表的主索引鍵。為了避免在這種雙重讀取操作期間修改索引,會鎖定在隱藏索引資料表中找到的列。當更新使用者建立的NDB
資料表中由唯一索引參照的列時,更新所執行的交易會對隱藏的索引資料表進行獨佔鎖定。這表示對相同(使用者建立的)NDB
資料表的任何讀取操作都必須等待更新完成。即使讀取操作的交易等級是READ COMMITTED
,也是如此。一種可以用來繞過可能封鎖讀取的方法是強制 SQL 節點在執行讀取時忽略唯一索引。這可以透過將
IGNORE INDEX
索引提示用作讀取資料表的SELECT
陳述式的一部分來完成(請參閱 第 10.9.4 節,「索引提示」)。由於 MySQL 伺服器會為NDB
中建立的每個唯一索引建立陰影排序索引,因此可以讀取排序索引,並避免唯一索引存取鎖定。產生的讀取與按主索引鍵提交的讀取一樣一致,傳回讀取該列時最後提交的值。透過排序索引讀取會降低叢集中資源的利用效率,並可能具有更高的延遲。
也可以透過查詢範圍而非唯一值來避免使用唯一索引進行存取。
回滾。沒有部分交易,也沒有交易的部分回滾。重複索引鍵或類似的錯誤會導致整個交易回滾。
此行為與其他交易儲存引擎(例如可能會回滾個別陳述式的
InnoDB
)的行為不同。交易和記憶體使用量。 如本章其他部分所述,NDB 叢集無法很好地處理大型交易;最好執行許多小型交易,每個交易包含少量操作,而不是嘗試執行包含大量操作的單一大型交易。在其他考量因素中,大型交易需要非常大量的記憶體。因此,許多 MySQL 陳述式的交易行為會受到影響,如下列清單所述:
TRUNCATE TABLE
在NDB
資料表上使用時不具備交易性。如果TRUNCATE TABLE
無法清空資料表,則必須重新執行直到成功。DELETE FROM
(即使沒有WHERE
子句) 具備 交易性。對於包含大量列的資料表,您可能會發現使用多個DELETE FROM ... LIMIT ...
語句來「分塊」刪除操作可以提高效能。如果您的目標是清空資料表,則您可能希望改用TRUNCATE TABLE
。ALTER TABLE 和交易。當複製
NDB
資料表作為ALTER TABLE
的一部分時,複製的建立是不具交易性的。(無論如何,當複製被刪除時,此操作會被回滾。)
交易和 COUNT() 函式。 當使用 NDB Cluster 複寫時,無法保證複本上
COUNT()
函式的交易一致性。換句話說,當在來源上執行一系列語句(INSERT
、DELETE
或兩者)以在單一交易中變更資料表中的列數時,在複本上執行SELECT COUNT(*) FROM
查詢可能會產生中間結果。這是因為資料表
SELECT COUNT(...)
可能會執行髒讀,而不是NDB
儲存引擎中的錯誤。(有關更多資訊,請參閱錯誤 #31321。)