記一次線上MySQL資料歸檔方案
阿新 • • 發佈:2020-12-30
由於線上的MySQL實時表資料量太大,即使建了索引查詢速度也不理想,上週下班前經理讓我對線上MySQL的七張源資料層面的實時表進行歸檔,現表僅保留近三天的資料,三天之前的資料全部歸檔到歷史表中
一、基本思想
考慮到按照時間進行歸檔,因此MySQL按時間建立分割槽表,並且動態維護每張歷史表的分割槽,將三天前的資料插入到歷史表中,根據時間的不同會落到不同的分割槽中;校驗資料量在沒有丟失的情況下刪除原表資料並記錄日誌。
二、前期準備
所謂磨刀不誤砍柴工,首先需要了解MySQL分割槽表的理論、如何建立分割槽表、如何動態維護分割槽表…
2.1 MySQL建立分割槽表
原表的欄位基本都是varchar
DROP TABLE IF EXISTS `aj_gaaj_archive `;
CREATE TABLE `aj_gaaj_archive `
(
...,
`BACKUP_TIME` date comment '歸檔日期'
) PARTITION BY RANGE (to_days(`BACKUP_TIME`))(
partition p20201224 values less than (to_days('20201225'))
);
檢視分割槽表的分割槽情況
SELECT partition_name part, partition_expression expr, partition_description descr, FROM_DAYS(partition_description) lessthan_sendtime, table_rows FROM INFORMATION_SCHEMA.partitions WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME = 'aj_gaaj_archive';
2.2 MySQL分割槽表維護
使用過hive
的都知道,hive
是可以進行動態分割槽的,根據資料的不同動態的新增分割槽,據瞭解MySQL不支援這種功能,因此需要我們手動的去增加分割槽,從一位老哥的部落格中拔下一段方便維護分割槽表的儲存過程 []
create procedure auto_set_partitions(in databasename varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
in tablename varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
in partition_number int, in partitiontype int, in gaps int)
L_END:
begin
declare max_partition_description varchar(255) default '';
declare p_name varchar(255) default 0;
declare p_description varchar(255) default 0;
declare isexist_partition varchar(255) default 0;
declare i int default 1;
-- 檢視對應資料庫對應表是否已經有手動分割槽[自動分割槽前提是必須有手動分割槽]
select partition_name
into isexist_partition
from information_schema.partitions
where table_schema = databasename
and table_name = tablename
limit 1;
-- 如果不存在則列印錯誤並退出儲存過程
if isexist_partition <=> '' then
select 'partition table not is exist' as "ERROR";
leave L_END;
end if;
-- 獲取最大[降序獲取]的分割槽描述[值]
select partition_description
into max_partition_description
from information_schema.partitions
where table_schema = databasename
and table_name = tablename
order by partition_description desc
limit 1;
-- 如果最大分割槽沒有,說明沒有手動分割槽,則無法建立自動分割槽
if max_partition_description <=> '' then
select 'partition table is error' as "ERROR";
leave L_END;
end if;
-- 替換前後的單引號[''兩個引號表示一個單引號的轉義]
-- set max_partition_description = REPLACE(max_partition_description, '''', '');
-- 或使用如下語句
set max_partition_description = REPLACE(max_partition_description - 1, '\'', '');
-- 自動建立number個分割槽
while (i <= partition_number)
do
if (partitiontype = 0) then
-- 每個分割槽按天遞增,遞增gaps天
set p_description = DATE_ADD(FROM_DAYS(max_partition_description), interval i * gaps day);
elseif (partitiontype = 1) then
-- 每個分割槽按月遞增,遞增gaps月
set p_description = DATE_ADD(FROM_DAYS(max_partition_description), interval i * gaps month);
else
-- 每個分割槽按年遞增,遞增gaps年
set p_description = DATE_ADD(FROM_DAYS(max_partition_description), interval i * gaps year);
end if;
-- 刪除空格
set p_name = REPLACE(p_description, ' ', '');
-- 例如10.20的記錄實際是less than 10.21
set p_description = DATE_ADD(p_description, interval 1 day);
-- 如果有橫杆替換為空
set p_name = REPLACE(p_name, '-', '');
-- 刪除時間冒號
set p_name = REPLACE(p_name, ':', '');
-- alter table tablename add partition ( partition pname values less than ('2017-02-20 10:05:56') );
set @sql = CONCAT('ALTER TABLE ', tablename, ' ADD PARTITION ( PARTITION p', p_name,
' VALUES LESS THAN (TO_DAYS(\'', p_description, '\')))');
-- set @sql=CONCAT('ALTER TABLE ', tablename ,' ADD PARTITION ( PARTITION p', p_name ,' VALUES LESS THAN (TO_DAYS(\'', p_description ,'\')))');
-- 列印sql變數
-- select @sql;
-- 準備sql語句
PREPARE stmt from @sql;
-- 執行sql語句
EXECUTE stmt;
-- 釋放資源
DEALLOCATE PREPARE stmt;
-- 遞增變數
set i = (i + 1);
end while;
end;
三、本地實施
因為歸檔的表屬於ODS級別,不得不慎重啊,稍有不慎就要跑路的