背景:生產環境,單表數據量在400W條,數據占空間約20G,無索引。
數據庫引擎使用的是InnoDB,InnoDB數據庫對於已經刪除的數據只是標記為刪除,並不真正釋放所占用的磁盤空間,所以InnoDB數據庫文件會不斷增長。
目標是根據創建時間,僅保留近一個月的記錄,最簡朴的sql語句如下:
DELETE FROM log_interface WHERE datediff(SYSDATE(), createdon) > 30;
根據執行計划查詢預計需要刪除300W條,所刪數據占空間約15G,根據以往經驗,直接用上述sql進行數據刪除需要超過十分鍾,影響過大。
1. 如果是要刪除整個表,使用命令 truncate table 效率最高;
2. 如果需要刪除的數據量沒有這么大,可以分多次刪除,每次操作使用 limit 限制刪除條數:
DELETE FROM log_interface WHERE datediff(SYSDATE(), createdon) > 30 limit 10000; -- 刪除一次數據大概需要10s
3. 以上操作都不適應我們當前的場景,我們需要刪除的數據超過表數據的50%,建議拷貝所需數據到臨時表,然后重命名原表為其他名字,重命名臨時表為原表名稱,具體sql如下:
CREATE TABLE `log_interface_bak` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id', `trance_id` varchar(64) DEFAULT NULL COMMENT '一條請求鏈路(Trace)的唯一標識', `span_id` varchar(64) DEFAULT NULL COMMENT '一個工作單元(Span)的唯一標識,必須值', `parent_span_id` varchar(64) DEFAULT NULL COMMENT '標識當前工作單元所屬的上一個工作單元,Root Span(請求鏈路的第一個工作單元)的該值為空', `hospital_name` varchar(64) DEFAULT NULL COMMENT '所屬醫院名稱', `hospital_id` varchar(64) DEFAULT NULL COMMENT '所屬醫院ID', `factory_id` int(11) DEFAULT NULL COMMENT '廠商id', `docking_id` int(11) DEFAULT NULL COMMENT '對接類型id', `basic_interface_info_id` int(11) DEFAULT NULL COMMENT '標准接口id', `interface_name` varchar(64) DEFAULT NULL COMMENT '接口名稱', `business_id` int(11) DEFAULT NULL COMMENT '業務標簽', `interface_call_time` datetime(3) DEFAULT NULL COMMENT '接口調用時間', `interface_response_time` bigint(20) DEFAULT NULL COMMENT '接口響應時間', `interface_response_state` tinyint(1) DEFAULT NULL COMMENT '接口響應狀態 0 失敗 1 成功', `interface_fail_reason` varchar(1024) DEFAULT NULL COMMENT '接口調用失敗原因', `input_param` text COMMENT '接口入參', `output_param` text COMMENT '接口出參', `remarks` varchar(1024) DEFAULT NULL COMMENT '備注', `deletion_state` char(1) DEFAULT '0' COMMENT '刪除狀態,0未刪除,1已刪除', `createdon` datetime(3) DEFAULT NULL COMMENT '創建時間', `createdby` varchar(64) DEFAULT NULL COMMENT '創建者', `modifiedon` datetime DEFAULT NULL COMMENT '修改時間', `modifiedby` varchar(64) DEFAULT NULL COMMENT '修改者', `is_basic_type` tinyint(1) DEFAULT NULL COMMENT '是否標准接口 0 否 1 是', `path` varchar(128) DEFAULT NULL COMMENT '請求地址', `flow` bigint(20) DEFAULT NULL COMMENT '數據流量', `business_log_tag` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11456328 DEFAULT CHARSET=utf8 COMMENT='接口日志(標准接口,醫院接口)記錄表';
將 log_interface 表中需要留存的數據備份到 log_interface_bak 表:
insert into log_interface_bak SELECT * FROM log_interface WHERE datediff( SYSDATE( ), createdon ) < 30; -- 耗時196.427s
對表進行重命名:
RENAME TABLE log_interface to log_interface_a , log_interface_old to log_interface; -- 耗時0.238s
最后刪除log_interface_a表。
參考文檔:http://mysql.rjweb.org/doc.php/deletebig