天天看點

pt-online-schema-change使用說明、限制與比較

如果正在看這篇文章,相信你已經知道自己的需求了。

建立一個和要執行 alter 操作的表一樣的新的空表結構(是alter之前的結構)

在新表執行alter table 語句(速度應該很快)

在原表中建立觸發器3個觸發器分别對應insert,update,delete操作

以一定塊大小從原表拷貝資料到臨時表,拷貝過程中通過原表上的觸發器在原表進行的寫操作都會更新到建立的臨時表

rename 原表到old表中,在把臨時表rename為原表

如果有參考該表的外鍵,根據alter-foreign-keys-method參數的值,檢測外鍵相關的表,做相應設定的處理

預設最後将舊原表删除

隻介紹部分常用的選項

<code>--host=xxx --user=xxx --password=xxx</code>

連接配接執行個體資訊,縮寫<code>-h xxx -u xxx -p xxx</code>,密碼可以使用參數<code>--ask-pass</code> 手動輸入。

<code>--alter</code>

結構變更語句,不需要 <code>alter table</code>關鍵字。與原始ddl一樣可以指定多個更改,用逗号分隔。

絕大部分情況下表上需要有主鍵或唯一索引,因為工具在運作當中為了保證新表也是最新的,需要舊表上建立 delete和update 觸發器,同步到新表的時候有主鍵會更快。個别情況是,當alter操作就是在c1列上建立主鍵時,delete觸發器将基于c1列。

子句不支援 rename 去給表重命名。

alter指令原表就不支援給索引重命名,需要先drop再add,在pt-osc也一樣。(mysql 5.7 支援 rename index old_index_name to new_index_name)

但給字段重命名,千萬不要drop-add,整列資料會丢失,使用<code>change col1 col1_new type constraint</code>(保持類型和限制一緻,否則相當于修改 column type,不能online)

子句如果是add column并且定義了not null,那麼必須指定default值,否則會失敗。

如果要删除外鍵(名 fk_foo),使用工具的時候外鍵名要加下劃線,比如<code>--alter "drop foreign key _fk_foo"</code>

<code>d=db_name,t=table_name</code>

指定要ddl的資料庫名和表名

<code>--max-load</code>

預設為<code>threads_running=25</code>。每個chunk拷貝完後,會檢查 show global status 的内容,檢查名額是否超過了指定的門檻值。如果超過,則先暫停。這裡可以用逗号分隔,指定多個條件,每個條件格式: <code>status名額=max_value</code>或者<code>status名額:max_value</code>。如果不指定max_value,那麼工具會這隻其為目前值的120%。

因為拷貝行有可能會給部分行上鎖,threads_running 是判斷目前資料庫負載的絕佳名額。

<code>--max-lag</code>

預設1s。每個chunk拷貝完成後,會檢視所有複制slave的延遲情況(<code>seconds_behind_master</code>)。要是延遲大于該值,則暫停複制資料,直到所有從的滞後小于這個值。<code>--check-interval</code>配合使用,指定出現從庫滞後超過 max-lag,則該工具将睡眠多長時間,預設1s,再檢查。如<code>--max-lag=5 --check-interval=2</code>。

熟悉percona-toolkit的人都知道<code>--recursion-method</code>可以用來指定從庫dsn記錄。另外,如果從庫被停止,将會永遠等待,直到從開始同步,并且延遲小于該值。

<code>--chunk-time</code>

預設0.5s,即拷貝資料行的時候,為了盡量保證0.5s内拷完一個chunk,動态調整chunk-size的大小,以适應伺服器性能的變化。

也可以通過另外一個選項<code>--chunk-size</code>禁止動态調整,即每次固定拷貝 1k 行,如果指定則預設1000行,且比 chunk-time 優先生效

<code>--set-vars</code>

使用pt-osc進行ddl要開一個session去操作,<code>set-vars</code>可以在執行alter之前設定這些變量,比如預設會設定<code>--set-vars "wait_timeout=10000,innodb_lock_wait_timeout=1,lock_wait_timeout=60"</code>。

因為使用pt-osc之後ddl的速度會變慢,是以預計2.5h隻能還不能改完,記得加大<code>wait_timeout</code>。

<code>--dry-run</code>

建立和修改新表,但不會建立觸發器、複制資料、和替換原表。并不真正執行,可以看到生成的執行語句,了解其執行步驟與細節,和<code>--print</code>配合最佳。。

<code>--execute</code>

确定修改表,則指定該參數。真正執行alter。--dry-run與--execute必須指定一個,二者互相排斥

這個很容易了解,pt-osc會在原表上建立3個觸發器,而一個表上不能同時有2個相同類型的觸發器,為簡單通用起見,隻能一棍子打死。

是以如果要讓它支援有觸發器存在的表也是可以實作的,思路就是:先找到原表觸發器定義;重寫原表觸發器;最後階段将原表觸發器定義應用到新表。

這其實是我的一個顧慮,因為如果update t1,觸發update t2,但這條資料還沒copy到t2,不就有異常了嗎?背景通過打開general_log,看到它建立的觸發器:

在原表上update,新臨時表上是replace into整行資料,是以達到有則更新,無則插入。同時配合後面的 insert ignore,保證這條資料不會因為重複而失敗。

假設 t1 是要修改的表,t2 有外鍵依賴于 t1,_t1_new 是 alter t1 産生的新臨時表。

這裡的外鍵不是看t1上是否存在外鍵,而是作為子表的 t2。主要問題在 rename t1 時,t1“不存在”導緻t2的外鍵認為參考失敗,不允許rename。

pt-osc提供<code>--alter-foreign-keys-method</code>選項來決定怎麼處理這種情況:

<code>rebuild_constraints</code>,優先采用這種方式

它先通過 alter table t2 drop fk1,add _fk1 重建外鍵參考,指向新表

再 rename t1 t1_old, _t1_new t1 ,交換表名,不影響用戶端

删除舊表 t1_old

但如果字表t2太大,以緻alter操作可能耗時過長,有可能會強制選擇 drop_swap。

涉及的主要方法在 <code>pt-online-schema-change</code> 檔案的 determine_alter_fk_method, rebuild_constraints, swap_tables三個函數中。

<code>drop_swap</code>,

禁用t2表外鍵限制檢查 <code>foreign_key_checks=0</code>

然後 drop t1 原表

再 rename _t1_new t1

這種方式速度更快,也不會阻塞請求。但有風險,第一,drop表的瞬間到rename過程,原表t1是不存在的,遇到請求會報錯;第二,如果因為bug或某種原因,舊表已删,新表rename失敗,那就太晚了,但這種情況很少見。

我們的開發規範決定,即使表間存在外鍵參考關系,也不通過表定義強制限制。

使用osc會使增加一倍的空間,包括索引

而且在 row based replication 下,還會寫一份binlog。不要想當然使用<code>--set-vars</code>去設定 sql_log_bin=0,因為在這個session級别,alter語句也要在從庫上執行,除非你對從庫另有打算。

online ddl在必須copy table時成本較高,不宜采用

pt-osc工具在存在觸發器時,不适用

修改索引、外鍵、列名時,優先采用online ddl,并指定 algorithm=inplace

其它情況使用pt-osc,雖然存在copy data

pt-osc比online ddl要慢一倍左右,因為它是根據負載調整的

無論哪種方式都選擇的業務低峰期執行

特殊情況需要利用主從特性,先alter從庫,主備切換,再改原主庫

借助percona部落格一張圖說明一下:

pt-online-schema-change使用說明、限制與比較

添加新列

完整輸出過程

修改列類型

添加删除索引

放背景執行

修改主鍵

1. 存在trigger

表上存在觸發器,不适用。

2. no-version-check

<a href="https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html">refman pt-online-schema-change</a>

<a href="https://help.aliyun.com/knowledge_detail/13098164.html">rds mysql 如何使用 percona toolkit</a>

<a href="http://www.cnblogs.com/zhoujinyi/p/3491059.html">percona-toolkit 之 【pt-online-schema-change】說明</a>

<a href="https://www.percona.com/blog/2014/11/18/avoiding-mysql-alter-table-downtime/">avoiding mysql alter table downtime</a>

<a href="http://www.imcjd.com/?p=1081">mysql online ddl和nosql schemaless design</a>