MDL,即元數據鎖是什么,我們已經介紹過了
那其存在的長事務讀寫阻塞問題,一般是怎么解決的呢,主要有兩種解決方法。
online ddl
MySQL5.6開始,推出一項新功能Online DDL,在ALTER或者CREATE INDEX等語句后添加了兩個參數:
ALTER TABLE user ADD INDEX idx_test_id (test_id), ALGORITHM=INPLACE, LOCK=NONE
ALGORITHM:
- INPLACE: 表的更改將在原表進行,而不用重建整個表格(在大多數情況下,不需要將數據復制到臨時表)
- COPY: 將數據復制到臨時表中,重建表格并重建二級索引(相當于傳統方法)
LOCK:
- NONE: Read and write operations are allowed during the altering process.
- SHARED: Only read operations are allowed during the altering operations (DML is not allowed).
- EXCLUSIVE: The entire table will be locked for both reading and writing (neither select nor DML are allowed).
ONLINE DDL的局限性
- 僅適用于InnoDB(語法上它可以與其他存儲引擎一起使用,如MyISAM,但MyISAM只允許algorithm =
copy,與傳統方法相同); - 無論使用何種鎖(NONE,共享或排它),在開始和結束時都需要一個短暫的時間來鎖表(排它鎖);參考這里
- 在添加/刪除外鍵時,應該禁用 foreign_key_checks 以避免表復制;
- 仍然有一些 alter 操作需要 copy 或lock 表(老方法), 有關哪些表更改需要表復制或表鎖定,請查看手冊;
- 如果在表上有 ON … CASCADE 或 ON …SET NULL 約束,則在 alter table 語句中不允許LOCK = NONE;
- Online DDL會被復制到從庫(同主庫一樣,如果 LOCK = NONE,從庫也不會加鎖),但復制本身將被阻止,因為 alter在從庫以單線程執行,這將導致主從延遲問題。
pt-online-schema-change
pt-osc 用于 alter table 時不鎖表,簡單地說,這個工具創建一個與原始表一樣的新的空表,并根據需要更改表結構,然后將原始表中的數據以小塊形式復制到新表中,然后刪除原始表,然后將新表重命名為原始名稱。在復制過程中,對原始表的所有新的更改(insert,delete,update)都將應用于新表,因為在原始表上創建了一個觸發器,以確保所有新的更改都將應用于新表。
pt-osc工作過程
- 創建一個和要執行 alter 操作的表一樣的新的空表結構(是alter之前的結構)
- 在新表執行alter table 語句(速度應該很快)
- 在原表中創建觸發器3個觸發器分別對應insert,update,delete操作
- 以一定塊大小從原表拷貝數據到臨時表,拷貝過程中通過原表上的觸發器在原表進行的寫操作都會更新到新建的臨時表(會限制每次拷貝數據的行數以保證拷貝不會過多消耗服務器資源,采用LOCK IN SHARE MODE來獲取要拷貝數據段的最新數據并對數據加共享鎖阻止其他會話修改數據,不過每次加S鎖的行數不多,很快就會被釋放)
- Rename原表到old表中,在把臨時表Rename為原表(整個過程只在rename表的時間會鎖一下表,其他時候不鎖表)
- 如果有參考該表的外鍵,根據alter-foreign-keys-method參數的值,檢測外鍵相關的表,做相應設置的處理
- 默認最后將舊原表刪除
PT-ONLINE-SCHEMA-CHANGE 的局限性
- 在使用此工具之前,應為表定義PRIMARY KEY或唯一索引,因為它是DELETE觸發器所必需的;
- 如果表已經定義了觸發器,則不支持pt-osc;(顯然不是不能有任何觸發器,只是不能有針對insert、update、delete的觸發器存在,因為一個表上不能有兩個相同類型的觸發器)
- 如果表具有外鍵約束,需要使用選項 --alter-foreign-keys-method ;
- 還是因為外鍵,對象名稱可能會改變(indexes names 等);
- 在Galera集群環境中,不支持更改MyISAM表,系統變量wsrep_OSU_method 必須設置為 TOI(total order isolation)。