問題:對於百萬級或千萬級的大表,如果需求修改表結構。要怎么做??
1)一般不建議修改大表的數據結構,可以采用擴展表或其他辦法來解決業務問題。能不改就不改;
2)直接 ALTER TABLE 肯定是不行的~,ALTER TABLE 會鎖表,會影響業務的正常運行。
注:即使加了ALGORITHM = INPLACE, LOCK = NONE選項,不鎖表。對於大表的操作 ALTER TABLE 還是相當耗時、耗性能的,不建議直接使用這個操作。
ALTER TABLE table_name ADD COLUMN field_name INT (11) UNSIGNED NULL DEFAULT 0 COMMENT '新字段', ALGORITHM = INPLACE, LOCK = NONE;
不能直接修改表的話,那要怎么做呢??下面是我最近更新線上某大表表結構的操作,內容僅供參與~
一、創建副表、修改副表表結構
CREATE TABLE new_table LIKE old_table; ALTER TABLE new_table ADD COLUMN field_name INT (11) UNSIGNED NULL DEFAULT 0 COMMENT '新字段' AFTER xxx_field;
二、備份舊表數據
大數據的備份建議用 into outfile 命令來操作
SELECT * FROM old_table INTO OUTFILE '/temp/old_table_backup.txt';
1)先用 SHOW VARIABLES LIKE 'secure%'; 命令看一下有沒有 into outfile 和 load data 操作權限;沒有的話,得改一下mysql的配置;
注:當secure_file_priv,=null時表示沒有outfile和infile的權限,=temp(目錄名)時表示outfile只能輸出到這個目錄,=''時,outfile可以輸出到任意目錄~
2)上面命令有可能會報 ERROR 1045 (28000): Access denied for user 'xxx'@'%' (using password: YES) 錯誤;原因是當前mysql用戶沒有服務器目錄的寫權限(上面代碼是寫到/temp/目錄里);
注:能使用 outfile 命令的盡量使用 outfile 命令,outfile命令的性能消耗要低一點
如果沒有權限或者不想備份到服務器里,那怎么辦呢?我們可以用本地的mysqldump工具遠程連接導出數據到本地
mysqldump -h rr-xxxxxxxxxx.mysql.rds.aliyuncs.com -u webuser -t -f -p --set-gtid-purged=off --default-character-set=utf8 --skip-triggers --skip-lock-tables prod_xxx old_table > D:/backup/old_table.sql
注:-t 表示只要數據,不要結構;-f 表示忽略錯誤;--skip-triggers 表示跳過觸發器,--skip-lock-tables 表示不要鎖表。
mysqldump 命令選項詳情:https://help.aliyun.com/knowledge_detail/41732.html?spm=a2c4g.11186631.2.13.2c047e53mfgl55
導出的時候,如果有從庫的話,要用從庫導出
三、刪除新表索引(很重要)
帶索引寫入會很慢、性能消耗高,要先刪除索引;網上用的 disable keys(禁用索引)親測無效,還是刪除索引吧。導入數據之后再重建索引;
ALTER TABLE `new_table` DROP INDEX `idx_xxx1`, DROP INDEX `idx_xxx2`, DROP INDEX `idx_xxx3`;
四、舊表數據導入到新表(如果是dump到本地的,本地建副表-》刪除索引-》source導入數據-》select ... outfile-》得到備份數據文件)
登錄遠程主庫(有寫入權限)
mysql -h rm-xxxx.mysql.rds.aliyuncs.com -u webuser -p
set names utf8; use prod_xxx;
登錄並選擇好數據庫后,現在導出數據(這是導入到線上的新表,不是本地的~~)
load data local infile 'D:/backup/old_table.txt' ignore into table new_table(field1,field2...);
注:注意要加上 local 關鍵字,不然可能會報錯;
load data 命令詳情說明:https://help.aliyun.com/document_detail/127794.html?spm=5176.13910061.sslink.19.58d45a49ChoPv5
五、導入成功后,重新索引
ALTER TABLE `new_table` ADD INDEX `idx_xxx1` (`xxx1`) USING BTREE;
ALTER TABLE `new_table` ADD INDEX `idx_xxx2` (`xxx2`) USING BTREE;
ALTER TABLE `new_table` ADD INDEX `idx_xxx3` (`xxx3`) USING BTREE;
建議分開建多個索引。當然一次性創建多個也是可以的,可能會慢一點~
六、停止舊表的寫入
停止寫入或找一個寫入少的時間
七、處理差異數據導入到新表
在我們處理數據的這段時間內,又有新數據寫入到報舊表
INSERT INTO new_table (field1, field2...) SELECT field1, field2... FROM old_table where id>=xxx
八、數據表重命名
ALTER TABLE old_table RENAME old_table_bak; ALTER TABLE new_table RENAME old_table;
舊表改一個臨時名,新表改回舊表的表名~
到此,大表的結構修改就完成了。(已改臨時名的舊表看情況可以刪除掉~)完。