隨着業務的發展,更改表結構變的越來越常見。一般情況下,我們通過alter table 之類的DDL語句就可以完成。然而當執行alter table 語句時,數據庫會對整個實例加鎖,阻塞業務的所有操作,當線上數據表數據量非常龐大時,阻塞時間將會非常長,這對於我們是無法容忍的。因此我們不能簡單粗暴地對原表執行alter table語句。
一、OSC操作
在線更改表結構有兩種方法:
1、主從切換。即先逐步下線從庫,在從庫上執行alter table 語句,完成後替換線上從庫,這樣一臺一臺修改,最後做一下主從切換,再進行一次結構修改。整個過程耗時很長,並且做主從切換時,風險也很大。
2、Online Scheme Change,即OSC。
簡單地來講,OSC實際上是建立一張新表,在新表上執行DDL操作,然後將原表的數據同步到新表中,最後把新表rename爲原表,並將原表刪除或備份。在數據的同步中,除了要複製原始數據,也要將操作過程中原表數據產生的變化進行記錄,以保證數據一致性,可以採用觸發器記錄更改。
整個OSC過程可以分爲幾個階段:
1、創建新表。
2、創建觸發器。
3、複製數據。
4、重放記錄。
5、重命名(rename)。
6、清理。
下面分別介紹這幾個階段。
1、創建新表。在dba的實際操作中,往往需要在開發機上寫出最終的表結構創建語句,然後通過ftp供dba下載操作。
2、創建觸發器。可以設置mysql的insert、update和delete觸發器,將更改保存到delta表中。delta表設計如下:
delta表保存了自增字段,更新類型(插入、更新、刪除),是否已經被重放這三個字段以及原表的所有字段。
觸發器觸發時,可以通過old和new關鍵字將更新之後的數據存儲到delta表中,供重放使用。
創建觸發器的代碼如下:
(1)插入觸發器
delta表中存儲插入的數據
(2)刪除觸發器
delta表中存儲刪除的數據
(3)更新觸發器
delta表中存儲的是更新之前的數據,更新之後的數據直接從原表獲取即可(避免同一條記錄被多次更新)
3、複製數據
將表數據從A導到B有好幾種方法,最常用的一種是insert into B select * from A,在執行該語句時,數據庫select的結果集加鎖,影響業務,因此我們不能採用這種方案。
實際上,我們可以使用select...into outfile和load data infile的組合來實現,這樣是不會對紀錄進行鎖定的。考慮到一個表的數據量可能很大,可以根據select limit 分批次導出數據,如下所示:
注意:導入導出數據需要有file權限,此外,路徑設置還需要考慮是否設置@@secure_file_priv變量。
4、重放記錄
從delta表中查詢所有未被重放的,對於插入類型,執行插入操作;刪除類型,執行刪除操作;更新類型,更新的最終值從原表獲取,條件從delta表中獲取。
注意,重放記錄至少需要執行兩次,第一次,在複製完數據完成之後;第二次,在rename之前,以保證數據一致性。
5、重命名
操作完成後,通過mysql的rename命令,將新表重命名爲原表,原表命名爲備份表。注意,rename是一個原子操作,需要將兩次重命名寫到一條命令裏。
6、清理
OSC操作完成後,將產生的備份表、觸發器、delta表等刪掉,以免影響下次使用。
二、總結
以上即爲OSC的全部過程,可以看出,精華就在於觸發器那一部分的使用,由於工具的複雜性,使用中還有一些注意事項:
1、此工具不是原子操作,如果某一點失敗,處理不好,會留下很多中間過程的垃圾文件,這些可能會影響下次OSC操作;
2、執行OSC操作的原表和新表不能更改字段順序,切記切記!
3、在執行之前,要對磁盤容量進行評估,因爲OSC會使用表一倍以上的空間。
4、表不能有外鍵,否則可能會出現意想不到的問題。
源自小哥:司馬迪