MySQL Online DDL的改進與應用

1 早期DDL實現原理(5.6.7以前 )

    Innodb早期支持經過copy table跟inplace的方式來執行DDL語句,其原理以下:mysql

  • copy table方式sql

    • 新建跟原表格一致的臨時表,並在該臨時表上執行DDL語句數據庫

    • 鎖原表,不容許DML,容許查詢服務器

    • 逐行數據從原表拷貝到臨時表中(這個過程是沒有排序的)多線程

    • 拷貝結束後,原表禁止讀操做,也就是原表此時不提供讀寫服務併發

    • 進行rename操做,完成DDL過程ide

  • inplace方式(fast index creation,僅針對索引的建立跟刪除)性能

    • 新建frm臨時文件測試

    • 鎖原表,不容許DML,容許查詢優化

    • 按照彙集索引的順序,查詢數據,找到須要的索引列數據,排序後插入到新的索引頁中

    • 原表禁止讀操做,也就是原表此時不提供讀寫服務

    • 進行rename操做,替換frm文件,完成DDL過程

    inplace在copy table的基礎上作了一個較大的改進,則是不須要copy整個表格,只須要在原來的ibd文件上,新建所須要的索引頁,這個過程比copy table節約極大的IO資源佔用 且 DDL SQL執行速度大大提升,減小了該表格不提供寫服務的時長。可是inplace僅支持索引的建立於刪除,不支持其餘的DDL操做,其餘的DDL操做,仍然是copy table方式執行。

    對於一個線上業務數據庫,不管是copy table方式仍是inplace方式,這裏仍然有一個明顯的弊端:操做期間涉及表格不提供寫服務!沒法對涉及到表格至下INSERT,UPDATE,DELETE操做,僅支持SELECT。

回到頂部(go to top)

2 Online DDL實現原理

    當表格發生DDL操做,可能會出現該表格數分鐘甚至數小時不可訪問,性能及響應異常,爲了有效改善這個狀況,MySQL 在5.6.7版本推出了Online DDL。(本文參考官網5.7版本的文檔整理及測試)。

 

    在online DDL中,也包含了copy跟inplace兩種方式,對於不支持Online DDL的DDL SQL,則採用COPY方式;對於支持Online DDL的DDL SQL,則採用Inplace方式,這裏的Inplace又區分爲2類:是否須要rebuild表格,判斷標準爲:是否修改行記錄格式。若是修改了行記錄格式,則須要rebuild表格,好比修改列類型、增減列等;若是沒有修改行記錄格式,僅修改表的元數據,則不須要rebuild表格,僅修改元數據 metadata,好比刪除索引、設置默認值及重命名列名等。詳細可見下圖,具體語法狀況見`第4部分`。

 

    那麼,新增的Online DDL內部是怎樣一個實現原理呢?(此處參考:http://blog.itpub.net/22664653/viewspace-2056953/)

    有3個階段:prepare、execute、commit。

  • PREPARE

    • 建立新的臨時frm文件

    • 持有EXCLUSIVE_MDL鎖,禁止讀寫

    • 根據alter類型,肯定執行方式(copy,rebuild,no-rebuild)

    • 更新數據字典的內存對象

    • 如果須要rebuild,分配row_log對象記錄的增量

    • 如果須要rebuild, 生成新的臨時ibd文件

  • EXECUTE

    • 下降EXCLUSIVE-MDL鎖,容許讀寫(copy 不容許寫)

    • 記錄ddl執行過程當中產生的增量row-log(僅rebuild類型須要)

    • 掃描old_table的彙集索引每一條記錄record

    • 遍歷新表的彙集索引和二級索引,逐一處理

    • 根據record構造對應的索引項

    • 將構造索引項插入sort_buffer塊

    • 將sort_buffer塊插入新的索引

    • 把row-log中的操做應用到新臨時表中,應用到最後一個Block

    • 這部分無操做

    • 若是是僅修改元數據:

    • 其餘,則是:

  • COMMIT

    • 升級到EXECLUSIVE-MDL鎖,禁止讀寫

    • 重作最後一部分的row_log增量

    • 更新innodb的數據字典表

    • 提交事務,寫redo日誌

    • 修改統計信息

    • rename 臨時的ibd文件、frm文件

    • DDL完成

    這裏注意下row-log,它是記錄 DDL在執行過程當中表格發生數據變動的操做,這樣就能夠保證執行DDL表格的併發性,在EXCUTE階段能夠正常提供寫服務,不發生堵塞,最後把row-log應用到新的表格上便可。

    在5.7.17版本上測試的時候,發現,支持inplace且須要rebuild的DDL,在DDL期間,若是數據發生修改,都是直接刷新到原來的ibd文件上,在測試環境中,給大表testddl刪除一個字段,這個過程當中INSERT 100w行記錄,能夠看到原有ibd文件增加了1G左右。

    這裏有個疑問,未肯定:row-log應該不是記錄行記錄的修改格式,由於這樣效率過慢,初步推測應該是僅記錄主鍵,而後根據主鍵查找應用到新表上。

 

    Online DDL能夠有效改善DDL期間對數據庫的影響:

  • Online DDL期間,查詢和DML操做在多數狀況下能夠正常執行,對錶格的鎖時間也會大大減小,儘量的保證數據庫的可擴展性;

  • 容許 in-place 操做的 DDL,避免重建表格佔用過多磁盤IO及CPU資源,減小對數據庫的總體負荷,使得在DDL期間,可以維持數據庫的高性能及高吞吐量;

  • 容許 in-place 操做的 DDL,比須要COPY到臨時文件的操做要更少佔用buffer pool,避免以往DDL過程當中性能的臨時降低,由於之前須要拷貝數據到臨時表,這個過程會佔用到buffer pool ,致使內存中的部分頻繁訪問的數據會被清理出去。

回到頂部(go to top)

3 Online DDL涉及參數及選項

3.1 innodb_online_alter_log_max_size

    online ddl過程當中發生DML時,會把數據修改狀況記錄到row-log中,而row-log的大小,則由 innodb_online_alter_log_max_size設定,默認爲128M,當表格較大且操做頻繁時,作DDL過程,可調大該參數,避免出現1799錯誤:

3.2 Online DDL語法

  •  Alter table …. , ALGORITHM [=] {DEFAULT|INPLACE|COPY}, LOCK [=] { DEFAULT| NONE| SHARED| EXCLUSIVE }

3.3 lock 選項

    該選項用於調整DDL加鎖的方式,一共有4個選項。

  • LOCK=EXCLUSIVE

    • 對整個表格添加獨佔鎖(x鎖),不容許查詢跟修改操做

  • LOCK=SHARED

    • 對整個表格添加(s鎖),容許查詢操做,可是不支持數據變動操做

  • LOCK=NONE

    • 不添加鎖,既容許查詢操做,也支持數據庫變動操做,該模式下併發最好

  • LOCK=DEFAULT

    • 沒有指定LOCK的時候,則是默認爲這個選項

    • 根據DDL的操做類型,最小程度的加鎖,儘量支持查詢及0DML操做

    • 首先判斷當前操做是否可使用NONE模式,若是不能,判斷是否可使用SHARED模式,若是不能,判斷是否可使用EXCLUSIVE模式

3.4 ALGORITHM選項

    DDL對數據庫性能的影響,很大程度受操做方式影響,好比是不是容許in-place,是否請求COPY操做,是否重建整個表格。好比某個表格,修改或者添加默認值,並不會影響到表格內部的數據,因此1s內就能夠完成;添加1個索引,須要幾十秒,應爲須要新增索引數據頁跟修改frm文件,可是不用rebuild表格數據;而修改列的數據類型是,可能須要幾分鐘甚至更多時間,由於其須要從新Rebuild整個表格,執行期間對CPU,IO及buffer pool大量申請資源。

 

    由DDL引發的INPLACE,COPY,REBUILD,能夠經過指定ALGORITHM來選擇(注意並不是全部DDL都支持in-place,詳見第4部分)

  • ALGORITHM=INPLACE

  • ALGORITHM=COPY

   這兩個選項中,INPLACE要比COPY性能好,由於INPLACE既不會記錄UNDO LOG,也不寫REDO LOG,同時執行期間提供DML操做。

回到頂部(go to top)

4 Online DDL支持語法狀況

    Online DDL對不一樣的DDL語句具備不一樣的執行規則,下面的表格將詳細描述各個語法對Online DDL的支持狀況。

列說明:

  • In-Place? 

    • 說明: 是否支持  ALGORITHM=INPLACE 

  • Rebuilds Table?

    • 說明:是否會重建表格

    • 重建表格分爲兩種方式:INPLACE跟COPY (原地修改或者複製到臨時文件修改)

    • 若是支持 ALGORITHM=INPLACE,那麼則是原地修改 INPLACE(淡×××標記)

    • 若是不支持 ALGORITHM=INPLACE,那麼則是COPY,拷貝到臨時文件修改,而且不支持UPDATE DELETE INSERT操做(深褐色標記)

  • Permits Concurrent DM

    • 說明: 是否支持在DDL期間併發對該表格操做DML SQL

    • 新增空間索引及全文索引時,不支持DML操做

    • 當容許時,能夠經過LOCK選項來控制是否要提供查詢或者修改操做

    • LOCK=NONE,支持查詢跟UPDATE INSERT DELETE操做

    • LOCK=SHARED,僅支持查詢

    • Only Modifies Metadata? 

    • 是否只修改元數據

回到頂部(go to top)

5 測試記錄

5.1 4個典型DDL操做分析

    針對是否支持INPLACE、是否須要REBUILD及是否僅修改metadata來分類,選取每類一個DDL SQL來測試,見下圖:

    

    考慮到varchar變化長度的問題,這裏加測多這一項。

5.1.1 DDL測試內容

  • 測試DB環境:表格名 tbddl,表格大小:1G ,500W行記錄

  • 測試流程:開啓事務查詢,不提交 => 執行DDL => 提交查詢事務 => 執行DML =>開啓事務,執行DML不提交 =>提交DML

  • 測試DDL SQL

    • ALTER TABLE tbddl MODIFY COLUMN ItemId VARCHAR(20); 

    • ALTER TABLE tbddl ADD xinysu int;

    • CREATE INDEX IX_PROID ON tbddl (providerid);

    • ALTER TABLE tbddl ALTER COLUMN xinysu SET DEFAULT 123456;

    • ALTER TABLE tbddl ALTER COLUMN ItemId VARCHAR(50); #UTF8字符集,3個字節一個字符,50個字符則是150個字節,小於256bytes  

    • ALTER TABLE tbddl ALTER COLUMN ItemId VARCHAR(100);  #UTF8字符集,3個字節一個字符,100個字符則是300個字節,大於256bytes

  • 測試關注點

    • 啓動與關閉 old_alter_table

    • prepare,commit階段的鎖是怎麼樣的

    • excute階段的鎖是怎麼樣的

    • 執行期間服務器的性能狀況(zabbix監控)

    • 執行期間數據庫的併發狀況(sysbench壓測)

5.1.2 DDL測試結論

    測試過程當中的截圖,不在此描述,直接粘貼測試結果,感興趣的筒子們,能夠自行測試。

    VARCHAR按字符存儲,每一個字符按照字符集來計算字節,UTF8是3個字節一個字符,當VARCHAR的字節數<256byte時,只須要1個byte來存儲實際長度,當VARCHAR字節數>=256時,則須要2個byte來存儲實際長度。舉例,UTF8字符集下的VARCHAR(10),假設存儲 N (0<=N<=10),則其佔用的字節數爲:N*3+1;UTF8字符集下的VARCHAR(100),假設存儲 N (0<=N<=100),則其佔用的字節數爲:N*3+2。

    理解了這一點後,就能夠理解 增加或縮短列的長度這列DDL的處理方式,假設列 VARCHAR(M)須要增大或縮小到VARCHAR(N),字符集是UTF8:

  • 當 3M<256,3N<256,存儲長度的字節不須要變化,都爲1,則不須要變更行記錄,僅須要修改元數據;

  • 當 3M>256,3N>256,存儲長度的字節不須要變化,都爲2, 則不須要變更行記錄,僅須要修改元數據;

  • 當 3M<256,3N>256,存儲長度的字節須要變化,由1變2, 則須要變更行記錄,Online DDL使用COPY TABLE方式;

  • 當 3M>256,3N>256,存儲長度的字節須要變化,由2變1,則須要變更行記錄,Online DDL使用COPY TABLE方式

 

5.2 同表格多個DDL處理

    在Online DDL以前,都會習慣性的把同個表格的全部DDL語句合併爲一個SQL語句,避免重複Rebuild、屢次加鎖致使不提供DML時長增長等弊端。

    可是,引入Online DDL後,須要有2點改觀:

  • 除了個別不支持inplace的DDL語句,其餘DDL語句在執行期間是不會加X鎖的,也就是表格仍然提供DML操做

  • 鎖的粒度,同個DDL語句中,按照最高級別的鎖處理

  • 維護的方便性

    這裏建議按照3類來處理(測試後的我的建議,僅供參考),見下圖。

  • 爲啥copy table單獨出來呢?

    • 由於這一類操做過程當中是不容許DML操做的,建議把這一類的合成單獨一條DDL SQL執行,不與IPLACE的DDL SQL合併;

  • 爲啥iplace的要分爲2類呢?

    • 方便維護

    • 僅元數據修改的DDL較快執行結束,爲了方便管理維護,不至於全部SQL貼一堆,僅元數據修改的DDL語句歸一類

    • 須要REBUILD的歸一類,避免重複rebuild,浪費磁盤IO跟CPU資源。

    

    舉個例子,如今上線項目,須要對錶格tbddl,1個字段由INT修改成VARCHAR,新增3個字段,2個索引,2個默認值,2個列增加長度,單獨的SQL 爲:

 

alter table tbddl alter column ItemId varchar(20);

 

ALTER TABLE tbddl ADD  su int;

ALTER TABLE tbddl ADD  xin varchar(40);

ALTER TABLE tbddl ADD  yu int;

 

CREATE INDEX IX_SU ON tbddl(SU);

CREATE INDEX IX_yu ON tbddl(yu);

 

ALTER TABLE tbddl ALTER COLUMN CreatedById SET DEFAULT 123456;

ALTER TABLE tbddl ALTER COLUMN ItemID SET DEFAULT 654321;

 

ALTER TABLE tbddl ALTER COLUMN CreatedByName VARCHAR(70);

ALTER TABLE tbddl ALTER COLUMN ModifiedByName VARCHAR(100);

 

 

測試建議如下執行方式:

 

alter table tbddl alter column ItemId varchar(20);

ALTER TABLE tbddl ADD su int ,ADD xin varchar(40) ,ADD  yu int,ALTER COLUMN ModifiedByName VARCHAR(100),add index ix_su(SU), add index ix_yu(yu);

ALTER TABLE tbddl ALTER COLUMN CreatedById SET DEFAULT 123456,ALTER COLUMN ItemID SET DEFAULT 654321,ALTER COLUMN CreatedByName VARCHAR(70);

5.3 DDL執行期間數據庫性能異常處理

    執行DDL期間,須要密切留意數據庫服務器的CPU及IO狀況,查看數據庫的鏈接池、慢查詢狀況,若是期間發生了異常,應該如何處理呢?

    假設如今給大表tbddl新增一列,新增的過程當中,發現影響到線上業務,須要緊急中止,能夠經過如下步驟操做:

  • show processlist;

  • kill 進程id;

    具體見截圖。

   

   

 

5.4 DDL執行期間數據庫宕機

    DDL期間,若是發生宕機狀況,會對數據庫的恢復啓動形成什麼影響呢?臨時文件還存在嗎? 恢復過程當中會自動執行未完成的DDL操做嗎?若是會,是怎麼處理?若是不會,再次手動建立會有影響嗎?

    在5.7.17版本上,測試了4類DDL SQL,當DDL執行過程當中,數據庫發生宕機,該DDL不會影響到數據庫的恢復啓動,同時,這個未完成的DDL語句不回自動執行,因爲宕機過程當中來不及清理臨時文件,因此數據庫恢復後,臨時文件依舊存在。DDL沒有commit,也就覺得這數據庫的數據字典和表格的元數據沒有發生修改,再次手動執行DDL語句,並不會報衝突。(這點跟部分博文的分析有些出入,本次測試版本是5.7.17版本)

    測試過程,這裏不作過多描述,直接貼上結論,感興趣的筒子們能夠自行測試,歡迎討論。

 

5.5 DDL對主從的影響

    DDL期間,假設該SQL執行的時間須要10h,除去waitting metadata lock的時間,rebuild或者inplace的時間須要5小時,那麼在從庫是單線程SQL THREAD應用relay log的狀況,須要考慮從庫滯後的影響。

    DDL在主庫執行狀況,因爲DDL語句沒有提交,因此不會同步到從庫上,從庫能夠正常同步其餘數據修改操做,這個環節沒有問題,可是當DDL在主庫提交後,該binlog日誌經過IO_THREAD傳送到從庫的RELAY LOG上,從庫的SQL_Thread是單線程工做,應用RELAY log的時候,至少須要5個小時,也就是這5個小時都用來執行RELAY LOG,沒法同步主庫幾個小時內產生的BIN LOG,那麼,從庫就會發生嚴重的滯後狀況,這個問題是否在可接受範圍內,須要歸入到DDL執行形成的影響範圍內。

    若是不能接受從庫這麼大的滯後,有什麼法子能夠處理呢?

    能夠經過這個思路來,從庫啓動並行複製。啓動並行複製,須要注意這幾個問題:

  • 使用注意

    • 在從庫嚴重落後主庫的狀況下,能夠開啓該參數實現多線程並行執行

    • 在業務量低的數據庫,不建議開啓,從庫同步性能反而會比拖累

  • 配置注意

    • database,不一樣庫的事務,觸發從庫並行回放

    • logical_clock,組提交事務,按照組提交設置,從庫並行回放,若是是爲了改善DDL的滯後狀況,應使用這個配置。

    • 注意 master_info_repository  relay_log_info_repository 設置爲 table,默認是寫入mater_info.log 及 relay_info.log ,刷下這兩個文件的頻率帶來的性能影響比較大,據 姜承驍姜老師 壓測,性能相差 20-50%間

    • slave_parallel_workers 建議設置爲從庫 核心 數

    • slave_parallel_type

回到頂部(go to top)

6 Online DDL注意事項

  • 磁盤空間

    • rebuild過程當中,產生的DML涉及到行記錄變動日誌,是否足夠存儲

    • 由於會拷貝ibd文件,因此要確保空間足夠

    • rebuild 的時候,datadir空間是否足夠

    • rebuild 的時候,innodb_online_alter_log_max_size是否足夠

    • inplace的時候,考慮tmpdir空間是否足夠

  • ddl對從庫延遲的影響是否能夠接受

    • 主庫online DDL的過程當中,因爲沒有commit,因此其餘併發操做能夠正常同步到從庫

    • 主庫commit後,DDL同步到從庫

    • 因爲從庫是單線程執行SQL_THREAD,假設DDL執行過程須要1個小時,那麼從庫將會滯後1小時+

    • 是否容許從庫的滯後,若是不容許,能夠經過並行複製來優化處理

  • row-log會檢查重複值或者修改衝突嗎?

    • 會根據主鍵及惟一約束來檢查

  • copy table ,inplace下如何暫停DDL操做

    • show full processlist;

    • kill id; #( DDL SQL的id號)

    • 這裏kill完後,仍然能夠再次正常執行DDL,不會存在衝突,其建立的臨時ibd及frm文件會自動刪除

  • copy table ,inplace下宕機

    • 這兩種狀況下宕機後,沒有完成的DDL語句不會繼續執行

    • 可是,其生成的frm跟 ibd 臨時文件不會被刪除,能夠手動刪除,也能夠不手動刪除,即便不刪除,也不會影響再次執行DDL

    • 但建議mysql服務後,刪除無用的臨時文件

  • 同個表格多個DDL語句,不要一個個執行

    • 請按照是否支持inplace及是否須要rebuild分類合併執行

  • 如何查看ddl進度(未解決)

    • 若是有rebuild,則是經過ibd文件的增加來評估;可是若是是inplace,如何查看呢?有沒有什麼比較好的方式查看?performance_schema是否有提供相應的查詢方式?

相關文章
相關標籤/搜索