MySQL online ddl原理

來源:互聯網
上載者:User

標籤:

背景

     dba的日常工作肯定有一項是ddl變更,ddl變更會鎖表,這個可以說是dba心中永遠的痛,特別是執行ddl變更,導致庫上大量線程處於“Waiting for meta data lock”狀態的時候。因此mysql 5.6的online ddl特性是dba們最期待的新特性,這個特性解決了執行ddl鎖表的問題,保證了在進行表變更時,不會堵塞線上業務讀寫,保障在變更時,庫依然能正常對外提供訪問。網上關於online ddl的文章很多,但涉及原理的很少,都是介紹文法之類的,本文將詳細介紹online ddl的原理,知其然,更要知其所以然。

ddl實現方式

      5.6 online ddl推出以前,執行ddl主要有兩種方式copy方式和inplace方式,inplace方式又稱為(fast index creation)。相對於copy方式,inplace方式不拷貝資料,因此較快。但是這種方式僅支援添加、刪除索引兩種方式,而且與copy方式一樣需要全程鎖表,實用性不是很強。下面以加索引為例,簡單介紹這兩種方式的實現流程。

   copy方式

   (1).建立帶索引的暫存資料表

   (2).鎖原表,禁止DML,允許查詢

   (3).將原表資料拷貝到暫存資料表(無排序,一行一行拷貝)

   (4).進行rename,升級字典鎖,禁止讀寫

   (5).完成建立索引操作

  inplace方式

   (1).建立索引的資料字典

   (2).鎖表,禁止DML,允許查詢

   (3).讀取叢集索引,構造新的索引項目,排序並插入新索引

   (4).等待開啟當前表的所有唯讀事務提交

   (5).建立索引結束

online ddl實現

      online方式實質也包含了copy和inplace方式,對於不支援online的ddl操作採用copy方式,比如修改列類型,刪除主鍵等;對於inplace方式,mysql內部以“是否修改記錄格式”為基準也分為兩類,一類需要重建表(修改記錄格式),比如添加、刪除列、修改列預設值等;另外一類是只需要修改表的中繼資料,比如添加、刪除索引、修改列名等。Mysql將這兩類方式分別稱為rebuild方式和no-rebuild方式。online ddl主要包括3個階段,prepare階段,ddl執行階段,commit階段,rebuild方式比no-rebuild方式實質多了一個ddl執行階段,prepare階段和commit階段類似。下面將主要介紹ddl執行過程中三個階段的流程。

Prepare階段:

  1. 建立新的臨時frm檔案
  2. 持有EXCLUSIVE-MDL鎖,禁止讀寫
  3. 根據alter類型,確定執行方式(copy,online-rebuild,online-norebuild)
  4. 更新資料字典的記憶體對象
  5. 分配row_log對象記錄增量
  6. 產生新的臨時ibd檔案

ddl執行階段:

  1. 降級EXCLUSIVE-MDL鎖,允許讀寫
  2. 掃描old_table的叢集索引每一條記錄rec
  3. 遍曆新表的叢集索引和二級索引,逐一處理
  4. 根據rec構造對應的索引項目
  5. 將構造索引項目插入sort_buffer塊
  6. 將sort_buffer塊插入新的索引
  7. 處理ddl執行過程中產生的增量(僅rebuild類型需要)

commit階段

  1. 升級到EXCLUSIVE-MDL鎖,禁止讀寫
  2. 重做最後row_log中最後一部分增量
  3. 更新innodb的資料字典表
  4. 提交事務(刷事務的redo日誌)
  5. 修改統計資訊
  6. rename臨時idb檔案,frm檔案
  7. 變更完成  

關鍵函數堆棧

拷貝資料

row_merge_build_indexes
     row_merge_read_clustered_index //拷貝全量                                   

   {

       遍曆老表的叢集索引                                            

       row_build //建立一個row

       row_merge_buf_add//將row加入到sort_buffer
       row_merge_insert_index_tuples //插入到新表(叢集索引+二級索引)
   }            
   row_log_table_apply //對於rebuild類型,處理增量                              

   {

       row_log_table_apply_insert   //以insert為例

       row_log_table_apply_convert_mrec //將buf項轉為tuple

       {

           插入叢集索引 //row_ins_clust_index_entry_low

          插入二級索引// row_ins_sec_index_entry_low          

       }

   }

修改表資料字典

commit_try_norebuild,commit_try_rebuild

 常見的ddl操作

類型

並發DML

演算法

備忘

添加/刪除索引

 

Yes

Online(no-rebuild)

全文索引不支援

修改default值

修改列名

修改自增列值

Yes

Nothing

僅需要修改中繼資料

添加/刪除列

交換列順序

修改NULL/NOT NULL

修改ROW-FORMAT

添加/修改主鍵

Yes

 

Online(rebuild)

由於記錄格式改變,需要重建表

修改列類型

Optimize table

轉換字元集

No

Copy

需要鎖表,不支援online

 若干問題

1.如何?資料完整性

使用online ddl後,使用者心中一定有一個疑問,一邊做ddl,一邊做dml,表中的資料不會亂嗎?這裡面關鍵組件是row_log。row_log記錄了ddl變更過程中新產生的dml操作,並在ddl執行的最後將其應用到新的表中,保證資料完整性。

2.online與資料一致性如何兼得

實際上,online ddl並非整個過程都是online,在prepare階段和commit階段都會持有MDL-Exclusive鎖,禁止讀寫;而在整個ddl執行階段,允許讀寫。由於prepare和commit階段相對於ddl執行階段時間特別短,因此基本可以認為是全程online的。Prepare階段和commit階段的禁止讀寫,主要是為了保證資料一致性。Prepare階段需要產生row_log對象和修改記憶體的字典;Commit階段,禁止讀寫後,重做最後一部分增量,然後提交,保證資料一致。

3.如何?server層和innodb層一致性

在prepare階段,server層會產生一個臨時的frm檔案,裡麵包含了新表的格式;innodb層產生了臨時的ibd檔案(rebuild方式);在ddl執行階段,將資料從原表拷貝到臨時ibd檔案,並且將row_log增量應用到臨時ibd檔案;在commit階段,innodb層修改表的資料字典,然後提交;最後innodb層和mysql層面分別重新命名frm和idb檔案。

參考文檔

http://hedengcheng.com/?p=405

http://hedengcheng.com/?p=421

http://hedengcheng.com/?p=148

 

 

MySQL online ddl原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.