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。)