MySQL 5.7 特性:Online DDL


MySQL DDL 的方法

MySQL 的 DDL 有很多種方法。

MySQL 本身自帶三種方法,分別是:copy、inplace、instant。

  • copy 算法為最古老的算法,在 MySQL 5.5 及以下為默認算法。
  • 從 MySQL 5.6 開始,引入了 inplace 算法並且默認使用。inplace 算法還包含兩種類型:rebuild-table 和 not-rebuild-table。MySQL 使用 inplace 算法時,會自動判斷,能使用 not-rebuild-table 的情況下會盡量使用,不能的時候才會使用 rebuild-table。當 DDL 涉及到主鍵和全文索引相關的操作時,無法使用 not-rebuild-table,必須使用 rebuild-table。其他情況下都會使用 not-rebuild-table。
  • 從 MySQL 8.0.12 開始,引入了 instant 算法並且默認使用。目前 instant 算法只支持增加列等少量 DDL 類型的操作,其他類型仍然會默認使用 inplace。

有一些第三方工具也可以實現 DDL 操作,最常見的是 percona 的 pt-online-schema-change 工具(簡稱為 pt-osc),和 github 的 gh-ost 工具,均支持 MySQL 5.5 以上的版本。

各類工具的對比

方法

copy

inplace not-rebuild-table

inplace rebuild-table

instant

pt-osc

gh-ost

DDL 過程中讀取數據

允許

允許

允許

允許

允許

允許

DDL 過程中寫入數據

不允許

允許

允許

允許

允許

允許

需要 MDL

需要

需要

需要

需要

需要

需要

需要額外空間

執行時間

非常長

非常長

非常短

IO 負載

非常小

非常大

導致主從同步延時

非常大

非常小

其他

         

支持臨時暫停

一般情況下的建議:

  • 如果使用的是 MySQL 5.5 或者 MySQL 5.6,推薦使用 gh-ost
  • 如果使用的是 MySQL 5.7,索引等不涉及修改數據的操作,建議使用默認的 inplace 算法。如果涉及到修改數據(例如增加列),不關心主從同步延時的情況下使用默認的 inplace 算法,關心主從同步延時的情況下使用 gh-ost
  • 如果使用的是 MySQL 8.0,推薦使用 MySQL 默認的算法設置,在語句不支持 instant 算法並且在意主從同步延時的情況下使用 gh-ost

各類工具的使用方法

copy

MySQL 5.5 及以下,直接正常 DDL 即可。

MySQL 5.6 及以上,如果希望使用 copy 算法,需要使用 ALGORITHM=COPY 指定算法類型,例如:

ALTER TABLE table1 ADD COLUMN column1 int ALGORITHM=COPY;

inplace

MySQL 5.7,直接正常 DDL 即可。

MySQL 8.0 及以上,如果希望使用 inplace 算法,需要使用 ALGORITHM=INPLACE 指定算法類型。

instant

MySQL 8.0 ,直接正常 DDL 即可。

pt-online-schema-change

比 gh-ost 落后很多,不推薦使用此工具。

gh-ost

參考其他的文章

MySQL DDL 的使用注意事項

MySQL 在大型表上的 DDL 會帶來耗時較久、負載較高、額外空間占用、MDL、主從同步延時等情況。需要特別引起重視。

大部分情況在上面的性能對比表格已經描述,這里不再重復,這里着重講一些重點問題:

DDL 的所需時間

DDL 的執行時間,和很多因素相關,如果需要比較精確的時間預估,建議在測試環境提前做測試。

可以新建一個測試實例,將備份數據導出到測試實例,執行 DDL 操作,判斷執行時間,作為對線上執行的一個估計。但是請注意,該估計仍然可能不准確,因為線上實例的負載可能會比測試實例高。

如果使用的是 gh-ost,工具會反饋執行進度。如果使用的是 MySQL 自帶的 DDL,MySQL 5.7 可以開啟 DDL 監控,使用以下語句查看 DDL 執行進度:

SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED FROM performance_schema.events_stages_current;

MySQL 自帶的監控也是估算值,因此進可作參考。

負載

所有方式對大表做 DDL 都會增加負載,只是程度的不同,主要為 IO 的負載。如果是 IO 使用非常高的實例,建議在 IO 較小的時間段執行 DDL 操作。

額外空間占用

copy、inplace rebuild-table、gh-ost、pt-online-schema-change,都會將表完整復制一份出來再做 DDL 變更,因此會使用和原表空間一樣大(甚至更大,如果是加列的操作的話)的額外空間,另外還會生成大量的臨時日志。要特別注意剩余空間,確保空間充裕,不然可能導致 DDL 過程中磁盤寫滿。

主從同步延時

所有方式做 DDL 均會引發主從同步延時。其中 copy 和 inplace 算法,只有主完成了 DDL 操作之后,binlog 才會同步給從庫,從庫才能開始操作 DDL,從庫操作完 DDL 之后才能開始操作其他語句,因此會造成巨大的(大概兩倍 DDL 操作時間)的延時。其他方法產生的延時較小,但仍然可能有幾秒的延時。

MDL

所有方式做 DDL 均會產生 MDL(metadata lock)。除了 copy 模式會有持續性的鎖(DDL 的整個過程期間無法向該表寫入任何數據)之外,其他方式的 MDL 均為短暫的鎖。

除了 copy 模式之外的所有模式,MDL 如下:

  1. 在 DDL 的開始階段,申請該表的 EXCLUSIVE-MDL 鎖,禁止讀寫
  2. 降級 EXCLUSIVE-MDL 鎖,允許讀寫
  3. 在 DDL 的最終 COMMIT 階段,升級 EXCLUSIVE-MDL 鎖,禁止讀寫

其中的階段一和階段三,其 MDL 的持續時間都是非常短暫的,也就是申請到了 MDL 鎖之后會在很快的時間(一般小於一秒)處理完成相關操作並釋放鎖,一般情況下是不會影響業務的。只有階段二是真正在處理數據,持續時間一般較長。

但是,有可能出現在階段一和階段三,無法申請到 MDL 的情況。這是因為 MDL 和所有的讀寫語句都可能會產生沖突,如果是在申請 MDL 的時候,之前有讀寫的事務一直沒有執行完成(或者執行完成之后一直沒有 COMMIT),MDL 就會無法立刻申請到,這個時候,DDL 語句,以及所有在該 DDL 語句之后的讀寫事務,都會阻塞並等待之前的讀寫事務完成,導致整個實例處於不可用狀態。這個時候 SHOW PROCESSLIST 看到的語句狀態為 waiting for metadata lock

由於目前所有的 DDL 語句都會產生 MDL,無法避免,因此,在執行 DDL 操作期間,盡可能確保不要有未執行完成的長事務。如果發生了 warting for metadata lock 導致的阻塞,一般有以下三種處理方法:

  1. 耐心等待之前的事務全部執行完成
  2. 將之前未執行完成的事務全部 kill 掉
  3. kill 掉 DDL 語句

其他

MySQL 的 inplace 算法雖然支持在 DDL 過程中間的讀寫,但是對寫入的數據量有上限,不能超過 innodb_online_alter_log_max_size(默認為 128M)。如果超過上限可能導致執行失敗。

MySQL DDL 的原理簡析

copy 算法

較簡單的實現方法,MySQL 會建立一個新的臨時表,把源表的所有數據寫入到臨時表,在此期間無法對源表進行數據寫入。MySQL 在完成臨時表的寫入之后,用臨時表替換掉源表。這個算法主要被早期(<=5.5)版本所使用。

inplace 算法

從 5.6 開始,常用的 DDL 都默認使用這個算法。inplace 算法包含兩類:inplace-no-rebuild 和 inplace-rebuild,兩者的主要差異在於是否需要重建源表。

inplace 算法的操作階段主要分為三個:

  • Prepare階段: - 創建新的臨時 frm 文件(與 InnoDB 無關)。 - 持有 EXCLUSIVE-MDL 鎖,禁止讀寫。 - 根據 alter 類型,確定執行方式(copy,online-rebuild,online-not-rebuild)。 更新數據字典的內存對象。 - 分配 row_log 對象記錄數據變更的增量(僅 rebuild 類型需要)。 - 生成新的臨時ibd文件 new_table(僅rebuild類型需要)。
  • Execute 階段:
    • 降級EXCLUSIVE-MDL鎖,允許讀寫。
    • 掃描old_table聚集索引(主鍵)中的每一條記錄 rec。
    • 遍歷new_table的聚集索引和二級索引,逐一處理。
    • 根據 rec 構造對應的索引項。
    • 將構造索引項插入 sort_buffer 塊排序。
    • 將 sort_buffer 塊更新到 new_table 的索引上。
    • 記錄 online-ddl 執行過程中產生的增量(僅 rebuild 類型需要)。
    • 重放 row_log 中的操作到 new_table 的索引上(not-rebuild 數據是在原表上更新)。
    • 重放 row_log 中的DML操作到 new_table 的數據行上。
  • Commit階段:
    • 當前 Block 為 row_log 最后一個時,禁止讀寫,升級到 EXCLUSIVE-MDL 鎖。
    • 重做 row_log 中最后一部分增量。
    • 更新 innodb 的數據字典表。
    • 提交事務(刷事務的 redo 日志)。
    • 修改統計信息。
    • rename 臨時 ibd 文件,frm文件。
    • 變更完成,釋放 EXCLUSIVE-MDL 鎖。

instant 算法

MySQL 8.0.12 才提出的新算法,目前只支持添加列等少量操作,利用 8.0 新的表結構設計,可以直接修改表的 metadata 數據,省掉了 rebuild 的過程,極大的縮短了 DDL 語句的執行時間。

pt-online-schema-change

借鑒了 copy 算法的思路,由外部工具來完成臨時表的建立,數據同步,用臨時表替換源表這三個步驟。其中數據同步是利用 MySQL 的觸發器來實現的,會少量影響到線上業務的 QPS 及 SQL 響應時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM