MariaDB10.3 系統版本表 有效防止數據丟失

系統版本表是SQL:2011標準中首次引入的功能。系統版本表存儲全部更改的歷史數據,而不只僅是當前時刻有效的數據。舉個例子,同一行數據一秒內被更改了10次,那麼就會保存10份不一樣時間的版本數據。就像《源代碼》電影裏的平行世界理論同樣,你能夠退回任意時間裏。從而有效保障你的數據是安全的,DBA手抖或程序BUG引發的數據丟失,在MariaDB10.3裏已成爲過去。php

1、建立系統版本表

例子:mysql

CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  `ts` timestamp(6) GENERATED ALWAYS AS ROW START,
  `te` timestamp(6) GENERATED ALWAYS AS ROW END,
  PRIMARY KEY (`id`,`te`),
  PERIOD FOR SYSTEM_TIME (`ts`, `te`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 WITH SYSTEM VERSIONING;

注意看紅色字體,這就是新增長的語法,字段ts和te是數據變化的起止時間和結束時間。sql

另外用ALTER TABLE更改表結構,語法以下:安全

ALTER TABLE t1 ADD COLUMN ts TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
              ADD COLUMN te TIMESTAMP(6) GENERATED ALWAYS AS ROW END,
              ADD PERIOD FOR SYSTEM_TIME(ts, te),
              ADD SYSTEM VERSIONING;

2、查詢歷史數據

這裏咱們作一個實驗,首先要插入1條數據,以下圖所示:
MariaDB10.3 系統版本表 有效防止數據丟失併發

接着把姓名爲「張三」,改爲「李四」(誤更改數據)
MariaDB10.3 系統版本表 有效防止數據丟失
如今數據已經成功變動,那麼我想查看歷史數據怎麼辦呢?很是簡單,一條命令搞定。ide

語法一:查詢一小時內的歷史數據。
SELECT * FROM t FOR SYSTEM_TIME BETWEEN (NOW() - INTERVAL 1 HOUR) AND NOW();
HOUR:小時
MINUTE:分鐘
DAY:天
MONTH:月
YEAR:年高併發

語法二:查詢一段時間內的歷史數據
SELECT * FROM t1 FOR SYSTEM_TIME FROM '2018-05-15 00:00:00' TO '2018-05-15 14:00:00';
MariaDB10.3 系統版本表 有效防止數據丟失工具

語法三:查詢全部歷史數據
SELECT * FROM t1 FOR SYSTEM_TIME ALL;
MariaDB10.3 系統版本表 有效防止數據丟失性能

3、恢復歷史數據

如今咱們已經找到了歷史數據「張三」,只需把它導出來作恢復便可。字體

SELECT id,name FROM t1 FOR SYSTEM_TIME ALL where id = 1 AND name = 
'張三' into outfile '/tmp/t1.sql' \
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"';

FIELDS TERMINATED BY ',' --- 字段的分隔符
OPTIONALLY ENCLOSED BY '"' --- 字符串帶雙引號

導入恢復

load data infile '/tmp/t1.sql' replace into table t1 \
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' \
(id,name);

MariaDB10.3 系統版本表 有效防止數據丟失
很是簡單的恢復完數據,此方法比以前用mysqlbinlog或自研腳本等工具作閃回效率高得多。

4、單獨存儲歷史數據

當歷史數據與當前數據一塊兒存儲時,勢必會增長表的大小,且當前的數據查詢:表掃描和索引搜索,將會花費更多的時間,由於須要跳過歷史數據。那麼咱們能夠將經過表分區將其分開、單獨存儲,以減小版本控制的開銷。
接上面的例子,執行下面的語句:

alter table t1 
  PARTITION BY SYSTEM_TIME INTERVAL 1 MONTH (
    PARTITION p0 HISTORY,
    PARTITION p1 HISTORY,
    PARTITION p2 HISTORY,
    PARTITION p3 HISTORY,
    PARTITION p4 HISTORY,
    PARTITION p5 HISTORY,
    PARTITION p6 HISTORY,
    PARTITION pcur CURRENT
  );

意思爲:按照月份分割歷史數據,今天至一個月後(2018年6月15日)的歷史數據放入p0分區,次月的歷史數據放入p1分區,依次類推至(2018年12月15日)存p6分區。當前數據存儲在pcur分區裏。
MariaDB10.3 系統版本表 有效防止數據丟失

MariaDB10.3 系統版本表 有效防止數據丟失

能夠經過數據字典表,來查看每一個分區表的數據輪詢時間狀態信息。

SELECT PARTITION_DESCRIPTION,TABLE_ROWS FROM 
`information_schema`.`PARTITIONS` WHERE table_schema='hcy' AND 
table_name='t1';

MariaDB10.3 系統版本表 有效防止數據丟失

5、刪除舊的歷史數據

系統版本表存儲了全部的歷史數據,隨着時間的推移,歷史版本數據會變得愈來愈大,那麼咱們就能夠將其最老的歷史數據刪除。
例:將p0分區刪除
ALTER TABLE t1 DROP PARTITION p0;
MariaDB10.3 系統版本表 有效防止數據丟失

6、正確使用姿式

經過上述介紹,咱們瞭解了系統版本表的原理。在高併發寫入場景下,勢必會帶來性能上的損失,因此要用正確的姿式開啓該功能。

例:主庫是MySQL 5.6或者MariaDB 10.0/1/2版本,搭建一個新從庫MariaDB 10.3,在該從庫上轉換爲系統版本控制表。這樣主庫上誤刪或誤篡改數據,能夠在從庫上經過版本控制找回。
MariaDB10.3 系統版本表 有效防止數據丟失
注:主庫是低版本,從庫是高版本,是能夠向前兼容binlog格式的。

7、注意事項

一、參數system_versioning_alter_history要設置爲KEEP(在my.cnf配置文件裏寫死),不然默認不能執行DDL修改表結構操做。
set global system_versioning_alter_history = 'KEEP';

注:增長字段時,要加上after關鍵字,不然會在te字段後面,形成同步失敗。例:
alter table t1 add column address varchar(500) after name;

二、mysqldump工具不會導出歷史數據,因此在作備份時,能夠經過Percona XtraBackup熱備份工具來備份物理文件。

三、搭建從庫時,若是你用mysqldump工具,要先導出表結構文件,再導出數據。
1)只導出表結構:
# mysqldump -S /tmp/mysql3306.sock -uroot -p123456 --single-transaction --compact -c -d -q -B test > ./test_schema.sql

導入完表結構後,批量執行DDL轉換系統版本表,腳本以下(附件裏點擊下載):

# cat convert.php 
<?php 

$conn=mysqli_connect("10.10.100.11","admin","123456","test","3306") or die("error connecting");
mysqli_query($conn,"SET NAMES utf8");

$table = "show tables";
$result1 = mysqli_query($conn,$table);
while($row = mysqli_fetch_array($result1)){
    $table_name=$row[0];
    echo "$table_name 表正在進行轉換系統版本表。。。".PHP_EOL;
    $convert_table="
ALTER TABLE {$table_name} ADD COLUMN ts TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
              ADD COLUMN te TIMESTAMP(6) GENERATED ALWAYS AS ROW END,
              ADD PERIOD FOR SYSTEM_TIME(ts, te),
              ADD SYSTEM VERSIONING";
    $result2=mysqli_query($conn,$convert_table);
    if($result2){
            echo '更改表結構成功.'.PHP_EOL;
           echo ''.PHP_EOL;
    }
    else{
            echo '更改表結構失敗.'.PHP_EOL;
           echo ''.PHP_EOL;
    }
}

mysqli_close($conn);

?>

注:先安裝php-mysql驅動
#yum install php php-mysql -y
#php convert.php
MariaDB10.3 系統版本表 有效防止數據丟失

2)只導出數據:

# mysqldump -S /tmp/mysql3306.sock -uroot -p123456 --single-transaction 
--master-data=2 --compact -c -q -t -B test > test_data.sql

參考文檔:
https://mariadb.com/kb/en/library/system-versioned-tables/

相關文章
相關標籤/搜索