MySQL——pt-online-schema-change工具的使用
阿新 • • 發佈:2021-11-24
作用:功能為在 alter 操作更改表結構的時候不用鎖定表,也就是說執行 alter 的時候不會阻塞寫和讀取操作
常見引數:
--alter指定ALTER 語句,正常的ALTER TABLE TBNAME [ ADD | MODIFY | DROP | ALTER ] COLUMN COLUMN_NAME ...,去除前面的ALTER TABLE TABLE那麼,直接指定後部分的內容
注意:rename 不支援,請直接使用renametabletable_nameto table_name_new;
如果表有資料,建立非空無預設值的列,會失敗;如果非空,需要指定預設值, 如果直接使用addcolumn num int, num這個列的預設值為NULL;
如果表有資料,為一個列新增預設值時,舊資料為NULL的是不會被修改,依舊為NULL,以後新加入的資料則會預設設定為預設值
對於外來鍵的刪除情況,由於執行是在新表上執行DDL,所以其外來鍵值的命名跟原表的命名不一樣,假設刪除原表的外來鍵名是 fk_foo,那麼新表的外來鍵名就為 _fk_foo,所以刪除的ALTER語句是: drop foreign key _fk_foo
--alter-foreign-keys-method 如果修改的表,是其他表外來鍵reference的表,那麼,最後rename的過程,需要確保一定成功,要不然這些子表就沒能成功reference到其指定的表名,對子表的操作將會報錯。比如 tba有一個外來鍵 fk_tba引用表格 tbb,這個時候tbb需要做DDL操作,根據pt工具的原理得知,最後會有一個rename環節,這個環節可能會導致約束失效或者執行堵塞等問題
針對最後的rename這個環節,該工具提供了4種處理方法:
auto 自動選擇rebuild_constraints 或者 drop_swap,優先選擇rebuild_constraints
rebuild_constraints:指在rename table前,先刪除子表的外來鍵約束,然後重建外來鍵約束指向到新表(ALTER TABLE語句新增),最後執行rename操作
注意:rename操作即使不成功,它也rename到新表,不會出現reference的表不存在情況,其弊端如果子表過大,新增外檢約束的過程中,可能會對子表造成阻塞
drop_swap:執行rename之前禁用外來鍵檢查,然後刪除原表,rename新表為原表名,這個執行過程非常快並且沒有阻塞
注意:需要強制指定 --no-swap-tables 跟 --no-drop-old-table,其弊端當把原表刪除而新表還沒rename為原表的名字時,這段時間實際非常短,但是這段時
間內,等於原表名的表是不存在的,子表做一些DML的時候,可能會出現錯誤。rename期間,如果新表rename原表失敗,但是已經刪除原表,那麼這段期間,其子表
的操作將會出現大面積問題,直到人工修復
none:類似於drop_swap,不同在於對原表的處理
按正常的pt工具流程,禁用外來鍵約束,rename原表為臨時表,rename新表為原表名,刪除臨時表
弊端: 當把原表rename為臨時表,而新表還沒rename為原表的名字時,這段時間實際非常短,但是這段時間內,等於原表名的表格時不存在的,子表做一些DML的時
候,可能會出現錯誤
--drop-old-tables 操作成功後,原表是否保留,預設是刪除;default:yes 可選:--no-drop-old-table
--dry-run 僅建立新表,但是不執行觸發器、拷貝資料和替換原表
--execute 確認執行alter操作,注意,這個操作如果不指定,則僅做安全檢查然後退出
--host 連線主機名
--max-lag 預設1秒
檢查從庫延遲的時間,如果超過,則停止copy data,休息--check-interval秒後,再重新開始copy資料;
檢視通過延遲時間,是通過從庫show slave status,檢視Seconds_Behind_Master;
如果指定--check-slave-lag,該工具只檢查該伺服器的延遲,而不是所有伺服器;
--check-interval 預設1秒
從庫延遲超過指定的--max-lag,中斷copy data休息的時間
--max-load 預設Threads_runing=25, --max-load=Threads_running=15
copy data的過程,監控資料庫當前正在執行的thread,如果超過指定的Threads_running值,則停止拷貝資料,會在輸出的內容中答應 Pausing because Threads_runing=15,直到執行的執行緒數小於給定的值,恢復copy data,如此迴圈,知道拷貝資料結束.
--password 資料庫使用者名稱密碼
--port 資料庫埠號
--socket 資料庫socket檔案
--user 資料庫使用者名稱
--recursion-method master尋找slave的方式,有4中方式
processlist show processlist
hosts show slave hosts
dsn=DNS DSNs from a table
none do not find slaves 不查詢從庫
注意:dsn,使用表格 tdsn儲存從庫資訊(DSN的具體引數選項可以詳細檢視 3.3 DSN選線)
需要手動在需要DDL的資料庫內,建立 dsns 表格
CREATE TABLE `dsns` (`id` int(11) NOT NULL AUTO_INCREMENT,`parent_id` int(11) DEFAULT NULL,`dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`));
儲存從庫資訊
insert into dsns(dsn) values(h=slave_host,u=repl_user,p=repl_password,P=port );
該引數使用的時候,按以下格式(假設 dsns表格建立在資料庫 dbosc)
--recursion-method dsn=D=dbosc,t=dsns
--statistics 增加影響行數列印,可以檢視copy進度
--print 詳細列印alter過程,不指定的時候,簡略列印
主庫準備資料:
create table t1 (id int, name varchar(10));
delimiter ;;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into t1 values(i,i);
set i=i+1;
end while;
end;;
delimiter ;
call idata();
安裝依賴:
yum -y install perl-DBI
yum -y install perl-DBD-MySQL
yum -y install perl-Time-HiRes
yum -y install perl-IO-Socket-SSL
檢視幫助文件
[root@db201 percona-toolkit-3.3.1]# ./bin/pt-online-schema-change --help
Can't locate Digest/MD5.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at ./bin/pt-online-schema-change line 6340.
BEGIN failed--compilation aborted at ./bin/pt-online-schema-change line 6340.
原因是缺少一個perl-Digest-MD5的包,只需要安裝即可:
yum -y install perl-Digest-MD5
[root@db201 ~]# /root/percona-toolkit-3.3.1/bin/pt-online-schema-change --socket=/root/data3307/my3307.sock --user=root --password=rootD=db1,t=t1 --alter "add column num int "--recursion-method=none --no-check-replication-filters --alter-foreign-keys-method auto --print --execute
Cannot connect to MySQL: DBI connect('db1;mysql_socket=/root/data3307/my3307.sock;mysql_read_default_group=client','root',...) failed: Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so: 無法開啟共享物件檔案: 沒有那個檔案或目錄 at /root/percona-toolkit-3.3.1/bin/pt-online-schema-change line 2345.
原因:mysql8.0.24的版本的加密插接default_authentication_plugin為caching_sha2_password;需要將加密外掛改為mysql_native_password
[root@db201 ~]# /root/percona-toolkit-3.3.1/bin/pt-online-schema-change --host=192.168.221.201 --user=root --password=rootP=3307,D=db1,t=t1 --alter "add column num int "--recursion-method=none --no-check-replication-filters --alter-foreign-keys-method auto --print --execute
No slaves found.See --recursion-method if host db201 has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
*******************************************************************
Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client
is deprecated! Please set SSL_verify_mode to SSL_VERIFY_PEER
possibly with SSL_ca_file|SSL_ca_path for verification.
If you really don't want to verify the certificate and keep the
connection open to Man-In-The-Middle attacks please set
SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.
*******************************************************************
at /root/percona-toolkit-3.3.1/bin/pt-online-schema-change line 7119.
*******************************************************************
Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client
is deprecated! Please set SSL_verify_mode to SSL_VERIFY_PEER
possibly with SSL_ca_file|SSL_ca_path for verification.
If you really don't want to verify the certificate and keep the
connection open to Man-In-The-Middle attacks please set
SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.
*******************************************************************
at /root/percona-toolkit-3.3.1/bin/pt-online-schema-change line 7119.
# A software update is available:
Cannot chunk the original table `db1`.`t1`: There is no good index and the table is oversized. at /root/percona-toolkit-3.3.1/bin/pt-online-schema-change line 6012.
原因是:t1表沒有主鍵或者唯一索引
——t1表新增主鍵 alter table t1 add primary key (id);後測試
——新增一列
[root@db201 ~]# /root/percona-toolkit-3.3.1/bin/pt-online-schema-change --host=192.168.221.201 --user=root --password=rootP=3307,D=db1,t=t1 --alter "add column num int"--recursion-method=none --no-check-replication-filters --alter-foreign-keys-method auto --print --execute
No slaves found.See --recursion-method if host db201 has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
No foreign keys reference `db1`.`t1`; ignoring --alter-foreign-keys-method.
Altering `db1`.`t1`...
Creating new table...
CREATE TABLE `db1`.`_t1_new` (
`id` int NOT NULL,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
Created new table db1._t1_new OK.
Altering new table...
ALTER TABLE `db1`.`_t1_new` add column num int
Altered `db1`.`_t1_new` OK.
2021-11-23T02:02:17 Creating triggers...
-----------------------------------------------------------
Event : DELETE
Name: pt_osc_db1_t1_del
SQL: CREATE TRIGGER `pt_osc_db1_t1_del` AFTER DELETE ON `db1`.`t1` FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR 1146 begin end; DELETE IGNORE FROM `db1`.`_t1_new` WHERE `db1`.`_t1_new`.`id` <=> OLD.`id`; END
Suffix: del
Time: AFTER
-----------------------------------------------------------
-----------------------------------------------------------
Event : UPDATE
Name: pt_osc_db1_t1_upd
SQL: CREATE TRIGGER `pt_osc_db1_t1_upd` AFTER UPDATE ON `db1`.`t1` FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR 1146 begin end; DELETE IGNORE FROM `db1`.`_t1_new` WHERE !(OLD.`id` <=> NEW.`id`) AND `db1`.`_t1_new`.`id` <=> OLD.`id`; REPLACE INTO `db1`.`_t1_new` (`id`, `name`) VALUES (NEW.`id`, NEW.`name`); END
Suffix: upd
Time: AFTER
-----------------------------------------------------------
-----------------------------------------------------------
Event : INSERT
Name: pt_osc_db1_t1_ins
SQL: CREATE TRIGGER `pt_osc_db1_t1_ins` AFTER INSERT ON `db1`.`t1` FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR 1146 begin end; REPLACE INTO `db1`.`_t1_new` (`id`, `name`) VALUES (NEW.`id`, NEW.`name`);END
Suffix: ins
Time: AFTER
-----------------------------------------------------------
2021-11-23T02:02:17 Created triggers OK.
2021-11-23T02:02:17 Copying approximately 100259 rows...
INSERT LOW_PRIORITY IGNORE INTO `db1`.`_t1_new` (`id`, `name`) SELECT `id`, `name` FROM `db1`.`t1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) AND ((`id` <= ?)) LOCK IN SHARE MODE /*pt-online-schema-change 40669 copy nibble*/
SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `db1`.`t1` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) ORDER BY `id` LIMIT ?, 2 /*next chunk boundary*/
2021-11-23T02:02:18 Copied rows OK.
2021-11-23T02:02:18 Analyzing new table...
2021-11-23T02:02:18 Swapping tables...
RENAME TABLE `db1`.`t1` TO `db1`.`_t1_old`, `db1`.`_t1_new` TO `db1`.`t1`
2021-11-23T02:02:18 Swapped original and new tables OK.
2021-11-23T02:02:18 Dropping old table...
DROP TABLE IF EXISTS `db1`.`_t1_old`
2021-11-23T02:02:18 Dropped old table `db1`.`_t1_old` OK.
2021-11-23T02:02:18 Dropping triggers...
DROP TRIGGER IF EXISTS `db1`.`pt_osc_db1_t1_del`
DROP TRIGGER IF EXISTS `db1`.`pt_osc_db1_t1_upd`
DROP TRIGGER IF EXISTS `db1`.`pt_osc_db1_t1_ins`
2021-11-23T02:02:18 Dropped triggers OK.
Successfully altered `db1`.`t1`.
注意:新新增的列,預設值為NULL
利用pt-online-schema-change 新增索引,檢視pt-online-schema-change 具體的執行流程
[root@db201 ~]# /root/percona-toolkit-3.3.1/bin/pt-online-schema-change --host=192.168.221.201 --user=root --password=rootP=3307,D=db1,t=t1 --alter "ADD INDEX name(name) "--recursion-method=none --no-check-replication-filters --alter-foreign-keys-method auto --print --execute
在執行之前,開啟set globalgeneral_log=1;檢視統一日誌,如下:
[root@db201 data]# cat db201.log
省略
由以上的日誌,可以看出具體的執行流程如下:
- 相關環境引數檢查;
- 檢查該表是否存在;
- show create table t1;
- CREATE TABLE `db1`.`_t1_new`
- ALTER TABLE `db1`.`_t1_new` ADD INDEX name(name)
- 建立刪除觸發器CREATE TRIGGER `pt_osc_db1_t1_del`
- 建立更新觸發器CREATE TRIGGER `pt_osc_db1_t1_upd`
- 建立插入觸發器CREATE TRIGGER `pt_osc_db1_t1_ins`
- 按塊拷貝資料到新表,拷貝過程中對資料行持有S鎖
- analyze新表ANALYZE TABLE `db1`.`_t1_new` /* pt-online-schema-change */
- rename表名RENAME TABLE `db1`.`t1` TO `db1`.`_t1_old`, `db1`.`_t1_new` TO `db1`.`t1`
- 刪除舊錶DROP TABLE IF EXISTS `db1`.`_t1_old`
- 刪除新表上的刪除,更新,插入觸發器 DROP TRIGGER IF EXISTS `db1`.`pt_osc_db1_t1_del`