Percona pt-archiver重構版--大表數據歸檔工具

Percona pt-archiver重構版--大表數據歸檔工具

相信不少小夥伴們,在平常對接開發時,有不少大表在業務上並無採起任何形式的切分,數據不停地往一張表裏灌入,早晚有一天,磁盤空間報警。做爲一個DBA,側重點是對數據庫的操做性能(大表增長字段/索引,QPS等)和存儲容量加以考慮,咱們會建議開發對數據庫裏的大表進行數據歸檔處理,例如將3個月內的訂單表保留在當前表,歷史數據切分後保存在歸檔表中,以後歸檔表從主庫上移走以便騰出磁盤空間,並將其遷移至備份機中(有條件的能夠將其轉換爲TokuDB引擎),以便提供大數據部門抽取至HDFS上。

一張大表,咱們姑且說1億條記錄,原表我要保存近7天的數據。Percona pt-archiver工具是這樣作的,逐條把歷史數據insert到歸檔表,同時刪除原表數據。7天數據好比說只有10萬行,那麼原表會直接刪除9990萬行記錄,操做成本過高,固須要考慮重構。

重構版是這樣作的,提取你要保留的7天數據至臨時表,而後老表和臨時表交換名字,這樣大大縮減了可用時間。

具體的工做原理:
一、若是表有觸發器、或者表有外鍵、或者表沒有主鍵或者主鍵字段默認不是id、或者binlog_format設置的值不是ROW格式,工具將直接退出,不予執行。

二、建立一個歸檔臨時表和原表同樣的空表結構。
php

CREATE TABLE IF NOT EXISTS ${mysql_table}_tmp like ${mysql_table};


三、在原表上建立增,刪,改三個觸發器將數據拷貝的過程當中,原表產生的數據變動更新到臨時表裏。
mysql

DROP TRIGGER IF EXISTS pt_archiver_${mysql_database}_${mysql_table}_insert;
CREATE TRIGGER pt_archiver_${mysql_database}_${mysql_table}_insert AFTER INSERT 
    ON ${mysql_table} FOR EACH ROW 
    REPLACE INTO ${mysql_database}.${mysql_table}_tmp ($column) VALUES ($new_column);
    
DROP TRIGGER IF EXISTS pt_archiver_${mysql_database}_${mysql_table}_update;
CREATE TRIGGER pt_archiver_${mysql_database}_${mysql_table}_update AFTER UPDATE 
    ON ${mysql_table} FOR EACH ROW 
    REPLACE INTO ${mysql_database}.${mysql_table}_tmp ($column) VALUES ($new_column);
    
DROP TRIGGER IF EXISTS pt_archiver_${mysql_database}_${mysql_table}_delete;
CREATE TRIGGER pt_archiver_${mysql_database}_${mysql_table}_delete AFTER DELETE 
    ON ${mysql_table} FOR EACH ROW 
    DELETE IGNORE FROM ${mysql_database}.${mysql_table}_tmp 
    WHERE ${mysql_database}.${mysql_table}_tmp.id <=> OLD.id;

這三個觸發器分別對應於INSERT、UPDATE、DELETE三種操做:
(1)INSERT操做,全部的INSERT INTO轉換爲REPLACE INTO,當有新的記錄插入到原表時,若是觸發器還未把該記錄同步到臨時表,而這條記錄以前因某種緣由已經存在了,那麼咱們就能夠利用REPLACE INTO進行覆蓋,這樣數據也是一致的;
(3)UPDATE操做,全部的UPDATE也轉換爲REPLACE INTO,若是臨時表不存在原表更新的該記錄,那麼咱們就直接插入該條記錄;若是該記錄已經同步到臨時表了,那麼直接進行覆蓋插入便可,全部數據與原表也是一致的;
(1)DELETE操做,原表有刪除操做,會觸發至臨時表執行刪除。若是刪除的記錄還未同步到臨時表,那麼能夠不在臨時表執行,由於原表中該行的數據已經被刪除了,這樣數據也是一致的。

四、拷貝原表數據到臨時表(默認1000條一批次插入並休眠1秒)
git

INSERT LOW_PRIORITY IGNORE INTO ${mysql_database}.${mysql_table}_tmp 
SELECT * FROM ${mysql_database}.${mysql_table} WHERE id>=".$begin_Id."
 AND id<".($begin_Id=$begin_Id+$limit_chunk)." LOCK IN SHARE MODE;


經過主鍵id進行範圍查找,分批次控制插入行數,已減小對原表的鎖定時間(讀鎖/共享鎖)---將大事務拆分紅若干塊小事務,若是臨時表已經存在該記錄將會忽略插入,而且在數據導入時,咱們能經過sleep參數控制休眠時間,以減小對磁盤IO的衝擊。

五、Rename原表爲_bak,臨時表Rename爲原表,名字互換。
github

RENAME TABLE ${mysql_table} to ${mysql_table}_bak, ${mysql_table}_tmp to ${mysql_table};


執行表更名字,會加table metadata lock元數據表鎖,但基本是瞬間結束,故對線上影響不大。

六、刪除原表上的三個觸發器。
sql

DROP TRIGGER IF EXISTS pt_archiver_${mysql_database}_${mysql_table}_insert;
DROP TRIGGER IF EXISTS pt_archiver_${mysql_database}_${mysql_table}_update;
DROP TRIGGER IF EXISTS pt_archiver_${mysql_database}_${mysql_table}_delete;


至此所有過程結束,相似pt-osc原理。

注:考慮到刪庫跑路等安全性問題,工具沒有對原表進行任何刪除歸檔數據的操做。
--------------------------------------------------------------------------------------------------------------------------------

使用
數據庫

# yum install php php-mysql -y


######下面的配置信息修改爲你本身的!!!######
安全

$mysql_server='10.10.159.31';
$mysql_username='admin'; 
$mysql_password='123456';
$mysql_database='test';
$mysql_port='3306';
$mysql_table='sbtest1';
###$where_column="update_time >= DATE_FORMAT(DATE_SUB(now(),interval 30 day),'%Y-%m-%d')";
$where_column="id>=99900000";
$limit_chunk='1000';     ###分批次插入,默認一批插入1000行
$insert_sleep='1';        ###每次插完1000行休眠1秒


###############################################

執行
bash

# php pt-archiver.php


工具下載地址:ide

https://pan.baidu.com/s/1uoBGWWh4CCLY5C8uM32DoA
工具


https://github.com/hcymysql/pt-archiver

相關文章
相關標籤/搜索