NDB Cluster 在處理交易方面存在一些限制。這些限制包括以下幾點:
交易隔離等級。
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 Cluster 備份疑難排解」,以瞭解 NDB Cluster 的交易隔離等級實作如何影響
NDB
資料庫的備份和還原。交易與 BLOB 或 TEXT 欄位。
NDBCLUSTER
僅將使用任何 MySQLBLOB
或TEXT
資料類型的欄位值部分儲存在 MySQL 可見的資料表中;BLOB
或TEXT
的剩餘部分儲存在 MySQL 無法存取的單獨內部資料表中。這會產生兩個相關的問題,您在對包含這些類型欄位的資料表執行SELECT
陳述式時應注意這些問題:針對任何來自 NDB Cluster 資料表的
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 節點在執行讀取時忽略唯一索引。這可以使用
SELECT
陳述式中作為一部分的IGNORE INDEX
索引提示來完成(請參閱第 10.9.4 節「索引提示」)。由於 MySQL 伺服器會為在NDB
中建立的每個唯一索引建立陰影順序索引,因此可以使用讀取順序索引來代替,並避免唯一索引存取鎖定。產生的讀取與依主索引鍵提交的讀取一致,並傳回讀取該列時最後一次提交的值。透過順序索引讀取會降低叢集中資源的使用效率,並可能具有更高的延遲。
也可以透過查詢範圍而不是唯一值來避免使用唯一索引進行存取。
復原。 沒有部分交易,也沒有部分交易復原。重複索引鍵或類似錯誤會導致整個交易復原。
交易與記憶體使用。 如本章其他地方所述,NDB Cluster 不擅長處理大型交易;執行多次每次包含少量操作的小型交易,會比嘗試執行包含大量操作的單一大型交易來得好。除此之外,大型交易需要非常大量的記憶體。因此,許多 MySQL 陳述式的交易行為會受到影響,如下列清單所述:
當在
NDB
資料表上使用TRUNCATE TABLE
時,它不具有交易性。如果TRUNCATE TABLE
無法清空資料表,則必須重新執行直到成功。DELETE FROM
(即使沒有WHERE
子句) 是 具有交易性的。對於包含大量資料列的資料表,您可能會發現使用多個DELETE FROM ... LIMIT ...
陳述式來將刪除操作「分塊」可提高效能。如果您的目標是清空資料表,則您可能希望改用TRUNCATE TABLE
。ALTER TABLE 和交易。 當複製
NDB
資料表作為ALTER TABLE
的一部分時,複製的建立不具有交易性。(無論如何,當複製被刪除時,此操作將會回滾。)
交易與 COUNT() 函式。 使用 NDB Cluster 複寫時,無法保證副本上
COUNT()
函式的交易一致性。換句話說,當在來源上執行一系列陳述式 (INSERT
、DELETE
或兩者),在單一交易中變更資料表中的資料列數目時,在副本上執行SELECT COUNT(*) FROM
查詢可能會產生中繼結果。這是因為table
SELECT COUNT(...)
可能會執行髒讀,而不是NDB
儲存引擎中的錯誤。(如需更多資訊,請參閱 Bug #31321。)