鏈接:https://cloud.tencent.com/developer/article/1524019
MySql數據庫大表添加字段的方法
第一 基礎方法
增加字段基本方法,該方法適合十幾萬的數據量,可以直接進行加字段操作。
ALTER TABLE tbl_tpl ADD title(255) DEFAULT '' COMMENT '標題' AFTER id;
但是,線上的一張表如果數據量很大,執行加字段操作就會鎖表,這個過程可能需要很長時間甚至導致服務崩潰,那么這樣操作就有風險。
第二 臨時表方法
思路如下:
① 創建一個臨時的新表,首先復制舊表的結構(包含索引)
create table new_table like old_table;
② 給新表加上新增的字段,注意,此時新表是空表,加字段很快;
③ 把舊表的數據復制過來
insert into new_table(filed1,filed2) select filed1,filed2 from old_table;
④ 刪除舊表,重命名新表的名字為舊表的名字
不過這里需要注意,執行第三步的時候,可能這個過程也需要時間,這個時候有新的數據進來,所以原來的表如果有字段記錄了數據的寫入時間就最好了,可以找到執行這一步操作之后的數據,並重復導入到新表,直到數據差異很小。不過還是會可能損失極少量的數據。
所以,如果表的數據特別大,同時又要保證數據完整,最好停機操作。
第三 使用pt-online-schema-change
介紹
pt-online-schema-change
是percona公司開發的一個工具,在percona-toolkit包里面可以找到這個功能,它可以在線修改表結構
原理:
- 首先它會新建一張一模一樣的表,表名一般是
_為前綴_new后綴
,例如原表為t_user
臨時表就是_t_user_new
- 然后在這個新表執行更改字段操作
- 然后在原表上加三個觸發器,
DELETE/UPDATE/INSERT
,將原表中要執行的語句也在新表中執行 - 最后將原表的數據拷貝到新表中,然后替換掉原表
SQL語句:
ALTER TABLE tmp_task_user ADD support tinyint(1) unsigned NOT NULL DEFAULT '1';
工具命令:
sh pt.sh tmp_task_user "ADD COLUMN support tinyint(1) unsigned NOT NULL DEFAULT '1'"
好處:
- 降低主從延時的風險
- 可以限速、限資源,避免操作時MySQL負載過高
建議:
- 在業務低峰期做,將影響降到最低
安裝
1.去官網下載對應的版本,官網下載地址:下載網址
查詢mysql版本 根據版本下載對應的軟件
select version();
2.下載
或者
百度雲下載
安裝
rpm -ivh percona-toolkit-3.1.0-2.el7.x86_64.rpm
安裝后位置
/bin/pt-online-schema-change
3.該工具需要一些依賴包,直接執行不成功時一般會有提示,這里可以提前yum安裝
yum list |grep Digest |grep MD5 yum install -y perl-Digest-MD5 yum list |grep Term |grep ReadKey yum install -y perl-TermReadKey.x86_64 yum list |grep DBI yum install -y perl-DBI yum list |grep DBD yum install -y perl-DBD-MySQL yum list |grep Time |HiRes yum install -y perl-Time-HiRes yum list |grep Socket |grep SSL yum install -y perl-IO-Socket-SSL
使用
1.參數
pt-online-schema-change --help
可以查看參數的使用,我們只是要修改個表結構,只需要知道幾個簡單的參數就可以了
–user= 連接mysql的用戶名 –password= 連接mysql的密碼 –host= 連接mysql的地址 P=3306 連接mysql的端口號 D= 連接mysql的庫名 t= 連接mysql的表名 –alter 修改表結構的語句 –execute 執行修改表結構 –charset=utf8 使用utf8編碼,避免中文亂碼 –no-version-check 不檢查版本,在阿里雲服務器中一般加入此參數,否則會報錯
2.為避免每次都要輸入一堆參數,寫個腳本復用一下 pt.sh
#!/bin/bash table=$1 alter_conment=$2 cnn_host='127.0.0.1' cnn_user='user' cnn_pwd='password' cnn_db='database_name' echo "$table" echo "$alter_conment" pt-online-schema-change --charset=utf8 --no-version-check --user=${cnn_user} --password=${cnn_pwd} --host=${cnn_host} P=3306,D=${cnn_db},t=$table --alter "${alter_conment}" --execute
添加執行權限
chmod +x pt.sh
3.添加表字段 如添加表字段SQL語句為:
ALTER TABLE `tb_test` ADD COLUMN `column1`tinyint(4) DEFAULT NULL;
那么使用pt-online-schema-change則可以這樣寫
sh pt.sh tb_test "ADD COLUMN column1 tinyint(4) DEFAULT NULL"
4.修改表字段
SQL語句:
ALTER TABLE `tb_test` MODIFY COLUMN `num` int(11) unsigned NOT NULL DEFAULT '0';
pt-online-schema-change工具:
sh pt.sh tb_test "MODIFY COLUMN num int(11) unsigned NOT NULL DEFAULT '0'"
5.修改表字段名 SQL語句:
ALTER TABLE `tb_test` CHANGE COLUMN age adress varchar(30);
pt-online-schema-change工具:
sh pt.sh tb_test "CHANGE COLUMN age address varchar(30)"
6.添加索引 SQL語句:
ALTER TABLE `tb_test` ADD INDEX idx_address(address);
pt-online-schema-change工具:
sh pt.sh tb_test "ADD INDEX idx_address(address)"
實際示例
ALTER TABLE t_question_bak DROP COLUMN docBase64,DROP COLUMN typeTextids,DROP COLUMN typeTextNames,DROP COLUMN kaofaid,DROP COLUMN kaofaname,DROP COLUMN topicNumber,DROP COLUMN docorder,DROP COLUMN corepointcode,DROP COLUMN corepointids,DROP COLUMN corepointcodes,DROP COLUMN pointnames,DROP COLUMN corepointnum,DROP COLUMN directorids,DROP COLUMN directornames,DROP COLUMN directorcodes; ALTER TABLE t_question_bak MODIFY COLUMN typeTextId INT(11) DEFAULT 0 COMMENT '題型ID(對應表t_subject_questiontype)';
pt-online-schema-change工具:
sh pt.sh t_question_bak "DROP COLUMN docBase64,DROP COLUMN typeTextids,DROP COLUMN typeTextNames,DROP COLUMN kaofaid,DROP COLUMN kaofaname,DROP COLUMN topicNumber,DROP COLUMN docorder,DROP COLUMN corepointcode,DROP COLUMN corepointids,DROP COLUMN corepointcodes,DROP COLUMN pointnames,DROP COLUMN corepointnum,DROP COLUMN directorids,DROP COLUMN directornames,DROP COLUMN directorcodes,MODIFY COLUMN typeTextId INT(11) DEFAULT 0 COMMENT '題型ID(對應表t_subject_questiontype)',ADD COLUMN belongtype int(2) DEFAULT 0"
刪除索引
sh pt.sh t_question_bak "DROP COLUMN docBase64,DROP COLUMN typeTextids,DROP COLUMN typeTextNames,DROP COLUMN kaofaid,DROP COLUMN kaofaname,DROP COLUMN topicNumber,DROP COLUMN docorder,DROP COLUMN corepointcode,DROP COLUMN corepointids,DROP COLUMN corepointcodes,DROP COLUMN pointnames,DROP COLUMN corepointnum,DROP COLUMN directorids,DROP COLUMN directornames,DROP COLUMN directorcodes,MODIFY COLUMN typeTextId INT(11) DEFAULT 0 COMMENT '題型ID(對應表t_subject_questiontype)',ADD COLUMN belongtype int(2) DEFAULT 0,DROP INDEX 上傳時間,DROP INDEX 試題科目,DROP INDEX 組題次數,DROP INDEX 刪除人員,DROP INDEX 審核時間,DROP INDEX 主鍵,DROP INDEX 題型ID,DROP INDEX 難易度,DROP INDEX 上傳人ID,DROP INDEX 所屬試卷類型ID,DROP INDEX 刪除人ID,DROP INDEX 試題來源類型,DROP INDEX 所屬學校ID,DROP INDEX 試卷ID,DROP INDEX 核心知識點ID,DROP INDEX question_testid,DROP INDEX 試題狀態,DROP INDEX ctyp值,DROP INDEX docHtml2,DROP INDEX q_docHtml2"
實際測試刪除索引后再修改表結構,效率將大大提升。 100W數據在不刪除索引的情況下50多分鍾才處理了50%,刪除索引后只用了2分鍾。
刪除表索引
生成刪除索引的SQL
# 拼接刪除索引的語法(排除主鍵索引) SELECT CONCAT('ALTER TABLE ',i.TABLE_NAME,' DROP INDEX ',i.INDEX_NAME,';') FROM INFORMATION_SCHEMA.STATISTICS i WHERE TABLE_SCHEMA = 'xhkj_ques_0923' AND TABLE_NAME='t_question' AND i.INDEX_NAME <> 'PRIMARY';
復制運行即可