實際問題系列:咱們是如何優雅修改正式環境的表結構,而不影響線上運行

這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰sql

在上一篇中介紹瞭如何優化慢sql,提升應用的速度,詳細的請移步優化系統慢查詢數據庫

文中案例說明須要在大表中添加一個字段group_id,表中有個1千萬的數據量,並且有幾個索引字段,若是直接在客戶端經過sql ALTER TABLE h_app_message ADD group_id bigint(20) 會形成數據庫卡頓,耗費時間很長,直接影響線上正常使用。markdown

通常對於較大數據量的修改方式,若是線上併發不是很高的狀況下是能夠手動處理的,方式以下:併發

  • 首先備份,備份,備份,重要的事情說三遍
  • 刪除表中的索引
  • 修改表結構
  • 修復數據
  • 恢復索引
  • 表結構修改完成

咱們的處理方式是經過pt-online-schame-change 工具在線修改正式環境的字段,添加group_id。app

此工具的好處:工具

下降主從延時的風險
能夠限速、限資源,避免操做時MySQL負載太高
複製代碼

建議:post

在業務低峯期作,將影響降到最低
複製代碼

直接原表修改缺點:測試

當表的數據量很大的時候,若是直接在線修改表結構,嚴重影響線上環境,並且耗時不可預估
複製代碼

注意:大數據

須要確認表必須包含主鍵或者惟一索引優化

工具會建立觸發器,因此原表上不能有觸發器

有外鍵的表須要注意使用參數--alter-foreign-keys-method(如今業務上不建議表中外鍵關聯,建議在業務中控制)

原理:

  • 首先它會新建一張如出一轍的表,表名通常是_new後綴
  • 而後在這個新表執行更改字段操做
  • 而後在原表上加三個觸發器,DELETE/UPDATE/INSERT,將原表中要執行的語句也在新表中執行
  • 最後將原表的數據拷貝到新表中,而後替換掉原表

1. 數據備份

不管操做多麼有把握,也要把備份作好(萬一很可怕的)

2. 安裝

下載安裝包:

wget  https://downloads.percona.com/downloads/percona-toolkit/3.3.1/source/tarball/percona-toolkit-3.3.1.tar.gz
複製代碼

解壓:

tar -xvf percona-toolkit-3.3.1.tar.gz
複製代碼

安裝一些依賴包:

yum install perl-DBIyum install perl-DBD-MySQLyum install perl-Time-HiResyum install perl-IO-Socket-SSLyum -y install perl-Digest-MD5
複製代碼

3. 測試可用

在解壓包的bin目錄下執行,看是否正常,查看命令

./pt-online-schema-change --help
複製代碼

4. 參數字段及含義

參數 含義
--user= 鏈接用戶名
--password= 鏈接密碼
--host= 鏈接IP
P= 端口
--alter= 執行表變動的語句
D= database 庫名
t= table 表名
--charset=utf8 使用utf8編碼,避免中文亂碼
--no-check-alter 不檢查alter語句
--print 打印操做日誌
--execute 執行修改表結構,真正的執行alter,–dry-run與–execute必須指定一個,兩者相互排斥
–dry-run 建立和修改新表,但不會建立觸發器、複製數據、和替換原表。並不真正執行,與--print配合查看執行細節

5. 具體操做

1. 添加一個字段

若是執行失敗,檢查alter語句,若是確認無誤 能夠避免檢查 --no-check-alter

./pt-online-schema-change --user=xxxx --password=xxxx --host=xxx.xxx.xxx.xxxx --alter "add column group_id bigint(20) not NULL default '0' comment 'test' " P=30306,D=h_pushcenter,t=h_message --charset=utf8 --no-version-check --print --execute
複製代碼

2. 修改字段

sql語句:

ALTER TABLE `h_message` MODIFY COLUMN `group_id` int(20)  NOT NULL DEFAULT '1';ALTER TABLE `h_message` MODIFY COLUMN `group_id` int(20)  NOT NULL DEFAULT '1';
複製代碼

pt命令:

--alter "MODIFY COLUMN group_id int(20) NOT NULL DEFAULT '1'"
複製代碼

3. 修改字段名

sql語句: 

ALTER TABLE `h_message` CHANGE column group_id group_id_0 bigint(20);
複製代碼

pt命令:

--alter "CHANGE group_id group_id_0 bigint(20)"
複製代碼

4. 添加索引

sql語句:

ALTER TABLE `h_message` ADD INDEX h_message_n1(group_id);
複製代碼

pt命令:

--alter "ADD INDEX h_message_n1(group_id)"
複製代碼

6. 操做日誌

  • 建立new結尾的新表
Creating new table...
CREATE TABLE `h_pushcenter`.`_h_message_new` .....
Created new table h_pushcenter._h_message_new OK.
複製代碼
  • 新表執行alter操做
Altering new table...
ALTER TABLE `h_pushcenter`.`_h_message_new` add column  group_id bigint(20) not NULL default '0'  comment 'test'
Altered `h_pushcenter`.`_h_message_new` OK.
複製代碼
  • 原表上建立3個觸發器
Creating triggers...
Event : DELETE
Event : UPDATE
Event : INSERT
Created triggers OK.
複製代碼
  • 複製數據到新表
Copying approximately 8187 rows...
Copied rows OK.
複製代碼
  • 重命名新舊兩個表,而後替換,刪除舊錶
2021-05-19T10:33:08 Swapping tables...
RENAME TABLE `h_pushcenter`.`h_message` TO `h_pushcenter`.`_h_message_old`, `h_pushcenter`.`_h_message_new` TO `h_pushcenter`.`h_message`
2021-05-19T10:33:09 Swapped original and new tables OK.
2021-05-19T10:33:09 Dropping old table...
DROP TABLE IF EXISTS `h_pushcenter`.`_h_message_old`
2021-05-19T10:33:09 Dropped old table `h_pushcenter`.`_h_message_old` OK.
複製代碼
  • 刪除觸發器
2021-05-19T10:33:09 Dropping triggers...
DROP TRIGGER IF EXISTS `h_pushcenter`.`pt_osc_h_pushcenter_h_message_del`
DROP TRIGGER IF EXISTS `h_pushcenter`.`pt_osc_h_pushcenter_h_message_upd`
DROP TRIGGER IF EXISTS `h_pushcenter`.`pt_osc_h_pushcenter_h_message_ins`
2021-05-19T10:33:09 Dropped triggers OK.
複製代碼
  • 打完收工

以上就是正式環境大數據表結構修改操做的使用方式,大家是怎麼處理大表結構修改的呢,歡迎留言告知, 有問題歡迎留言告知!

相關文章
相關標籤/搜索