日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql5.6最好的备份方案_Mysql 5.6迁移至PostgreSQL 9.6的实践小结

發(fā)布時間:2024/10/14 数据库 64 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql5.6最好的备份方案_Mysql 5.6迁移至PostgreSQL 9.6的实践小结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、背景

實際生產(chǎn)中,發(fā)現(xiàn)mysql查詢性能存在抖動,同樣的sql,正常執(zhí)行時間是秒級,但是偶爾會有執(zhí)行上百秒的情況出現(xiàn),經(jīng)過DBA的排查,并沒有發(fā)現(xiàn)mysql的問題。考慮遷移一部分生成數(shù)據(jù)到PG中進行測試。(ps~個人覺得這個遷移背景有點牽強,還是應(yīng)該先定位性能抖動的原因比較好)

二、遷移方案

遷移的大致步驟如下:

從生產(chǎn)環(huán)境的mysql備份中拉取一個備份出來

在測試機上通過備份恢復(fù)生產(chǎn)庫

導(dǎo)出mysql的表定義和數(shù)據(jù)

通過自己開發(fā)的小工具,將mysql表定義語法轉(zhuǎn)換至PG的表定義語法

在PG中創(chuàng)建表

將數(shù)據(jù)導(dǎo)入PG

三、遷移步驟說明

3.1 拉取備份

這個沒什么好說的,scp指定的備份文件到測試機即可

考慮是生產(chǎn)環(huán)境,有防火墻和權(quán)限等的限制,可以臨時創(chuàng)建臨時用戶tmp,關(guān)閉防火墻,待拷貝完成,刪除用戶,重啟防火墻

3.2 恢復(fù)生產(chǎn)庫

生產(chǎn)上通過xtrabackup做的備份,恢復(fù)方法這里就不啰嗦了,不是本次的重點,自行百度~

3.3 導(dǎo)出mysql的表定義和數(shù)據(jù)

從這步開始就有坑了~

首先,導(dǎo)出表定義(只貼出測試數(shù)據(jù))

# 將名為test_db的庫中所有的ddl都導(dǎo)出到test_db.sql文件中

# 導(dǎo)出的定義以sql語句的形式寫入文件

[mysql@sndsdevdb01 ~]$ mysqldump -h127.0.0.1 -uroot -ppassword -d test_db > /mysql/test_db.sql

[mysql@sndsdevdb01 ~]$ cat /mysql/test_db.sql

...

/* 下面是導(dǎo)出的表定義部分 */

DROP TABLE IF EXISTS `tb1`;

/*!40101 SET @saved_cs_client = @@character_set_client */;

/*!40101 SET character_set_client = utf8 */;

CREATE TABLE `tb1` (

`c1` int(11) DEFAULT NULL,

`c2` char(5) DEFAULT NULL,

`c3` varchar(10) DEFAULT NULL,

`c4` datetime DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

/*!40101 SET character_set_client = @saved_cs_client */;

SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;

/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

...

導(dǎo)出表定義是為了之后人工檢查mysql到PG的ddl語法轉(zhuǎn)換的正確性

實際實施時,利用小工具直接連接mysql服務(wù)器即可完成mysql到PG的ddl語法轉(zhuǎn)換

關(guān)于小工具的說明,請見附錄~

然后,導(dǎo)出數(shù)據(jù)

考慮到數(shù)據(jù)格式,編碼的問題,決定統(tǒng)一將數(shù)據(jù)導(dǎo)出為UTF8編碼的csv文件

為了說明坑的地方,我插入了5條記錄

mysql> delete from tb1;

Query OK, 3 rows affected (0.01 sec)

mysql> insert into tb1 values(1,'qqq','www',current_time);

Query OK, 1 row affected (0.02 sec)

mysql> insert into tb1 values(1,'qq\nq','www',current_time);

Query OK, 1 row affected (0.01 sec)

mysql> insert into tb1 values(1,'qq\r\nq','www',current_time);

Query OK, 1 row affected (0.00 sec)

mysql> insert into tb1 values(1,'qqq','www','0000-00-00 00:00:00');

Query OK, 1 row affected (0.00 sec)

mysql> insert into tb1 values(1,'qqq','www',null);

Query OK, 1 row affected (0.00 sec)

mysql> select * from tb1;

+------+-------+------+---------------------+

| c1 | c2 | c3 | c4 |

+------+-------+------+---------------------+

| 1 | qqq | www | 2017-07-14 17:36:25 |

| 1 | qq

q | www | 2017-07-14 17:36:30 |

| 1 | qq

q | www | 2017-07-14 17:36:36 |

| 1 | qqq | www | 0000-00-00 00:00:00 |

| 1 | qqq | www | NULL |

+------+-------+------+---------------------+

5 rows in set (0.00 sec)

mysql> select * from tb1 into outfile '/mysql/tb1.csv' fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\n';

其中第二條和第三條中,c2列分別包含了換行符和windows的特殊換行符

然后再通過vi 打開tb1.csv

1,"qqq","www","2017-07-14 17:36:25"

1,"qq"

q","www","2017-07-14 17:36:30"

1,"qq^M"

q","www","2017-07-14 17:36:36"

1,"qqq","www","0000-00-00 00:00:00"

1,"qqq","www","N

坑點如下

\n換行符導(dǎo)致原本的一條記錄分為2行

\r是特殊字符,vi模式下就表示為^M

datetime類型可以存儲"0000-00-00 00:00:00",但是官方手冊上datetime的合法范圍是'1000-01-0100:00:00' to '9999-12-31 23:59:59',感覺是bug。。

NULL值會被轉(zhuǎn)義為"N的形式

1和2兩點,導(dǎo)致csv格式混亂,導(dǎo)入PG會出錯;datetime對應(yīng)PG的timestamp類型,而"0000-00-00 00:00:00"是不符合PG的時間戳類型的合法范圍的;PG也不認(rèn)識"N表示的NULL。。。

由于上述的坑都是在將數(shù)據(jù)導(dǎo)入PG的時候才發(fā)現(xiàn)的,所以我的做法是通過shell的sed,awk等命令,去人工替換這些內(nèi)容。因為生產(chǎn)數(shù)據(jù)量很大,一個庫大概200G,磁盤空間有限,加上導(dǎo)出數(shù)據(jù)需要較長時間,所以盡量不重復(fù)導(dǎo)數(shù)據(jù)

但是用shell處理大文件,效率也很低,150G的csv文件,遍歷sed多次,往往超過1小時,而且存在正則表達(dá)式寫的不精確,匹配出錯的情況

所以我個人推薦,select導(dǎo)出數(shù)據(jù)時,通過where條件過濾,用replace函數(shù)將需要處理的列直接處理掉,可以省去后面的麻煩,但是前提條件是需要知道有哪些列存在這些問題(生成中的表往往列很多,幾十甚至幾百列)

3.3 在PG中創(chuàng)建表并導(dǎo)入數(shù)據(jù)

首先創(chuàng)建相應(yīng)的業(yè)務(wù)庫

postgres=# create database test_db;

CREATE DATABASE

postgres=# \c test_db

You are now connected to database "test_db" as user "postgres".

postgres=#\i /pgsql/pg.sql

# 執(zhí)行轉(zhuǎn)換后的ddl,定義表

...

postgres=#\copy tb1 from '/pgsql/tb1.csv' with(format csv,encoding 'UTF8',NULL 'null')

# 通過copy命令導(dǎo)入數(shù)據(jù),通過指定NULL字符串來識別NULL值

如果導(dǎo)入過程不出現(xiàn)任何錯誤,那說明數(shù)據(jù)的遷移基本就完成了

3.4 其他

上述內(nèi)容只是單純的業(yè)務(wù)庫的數(shù)據(jù)遷移,如果想完整的把整個業(yè)務(wù)系統(tǒng)遷移至PG,還有很多的別的遷移工作

例如表的索引

PG提供了豐富的索引類型,索引詳情參考:

PG 9.6 手冊 http://www.postgres.cn/docs/9.6/indexes.html

需要根據(jù)業(yè)務(wù)需求重新定制,例如AP型業(yè)務(wù),gin索性就有很大的優(yōu)勢,除此之外,業(yè)務(wù)定義的存儲過程,上層的增刪改查接口等等也需要修改

另外,數(shù)據(jù)庫的備份方案,日志歸檔設(shè)置,高可用方案的設(shè)計這些也需要定制

附錄

關(guān)于DDL語法轉(zhuǎn)換的小工具

功能簡述

將mysql的表定義轉(zhuǎn)換為PG對應(yīng)的語法。主要完成數(shù)據(jù)類型的映射,列屬性語法的轉(zhuǎn)換,主鍵和部分類型索引的轉(zhuǎn)換

1.1. 類型映射

case "tinyint":

case "tinyint unsigned":

case "smallint":

if (col_is_auto_increment.equals("YES")){//increment type

mysql_type.add("smallserial");

}else{

mysql_type.add("smallint");

}

break;

case "mediumint":

case "smallint unsigned":

case "mediumint unsigned":

case "integer":

case "int":

if (col_is_auto_increment.equals("YES")){//increment type

mysql_type.add("serial");

}else{

mysql_type.add("int");

}

break;

case "int unsigned":

case "bigint":

if (col_is_auto_increment.equals("YES")){//increment type

mysql_type.add("bigserial");

}else{

mysql_type.add("bigint");

}

break;

case "bigint unsigned":

mysql_type.add("decimal");

mysql_type.add("20");

mysql_type.add("0");

break;

case "double":

mysql_type.add("double precision");

break;

case "decimal":

mysql_type.add("decimal");

mysql_type.add(precision.toString());

mysql_type.add(scale.toString());

break;

case "float":

mysql_type.add("real");

break;

case "binary":

case "char":

mysql_type.add("char");

mysql_type.add(precision.toString());

break;

case "varbinary":

case "varchar":

mysql_type.add("varchar");

mysql_type.add(precision.toString());

break;

case "tinyblob":

case "mediumblob":

case "longblob":

case "blob":

mysql_type.add("bytea");

break;

case "date":

mysql_type.add("date");

break;

case "datetime":

case "year":

case "timestamp":

mysql_type.add("timestamp");

break;

case "time":

mysql_type.add("time");

break;

/*case "bit":

pg_type.add("bit");

break;*/

case "tinytext":

case "text":

case "mediumtext":

case "longtext":

mysql_type.add("text");

break;

default:

mysql_type.add("This type may be user deifned type,confirm for yourself please!");

break;

1.2. 列屬性

* not null屬性

* column注釋

* 自增屬性

1.3. 索引

統(tǒng)一將mysql的索引轉(zhuǎn)換為PG的btree索引,這個在應(yīng)用中意義不大,因為多數(shù)情況,索引是需要根據(jù)業(yè)務(wù)需求重新定義的

實現(xiàn)方式

通過JDBC連接mysql服務(wù)器,通過元數(shù)據(jù)(metadata)獲取所有的表名,列名以及列的數(shù)據(jù)類型等等信息,然后在程序中做轉(zhuǎn)換,最后寫入sql文件

思考

其實這只是簡單的遷移方案,目前也有一些商用或者開源的遷移工具,例如:

mysql2pg:https://sourceforge.net/projects/mysql2pg/

另外,關(guān)于遷移數(shù)據(jù),用csv文件的方式,對磁盤空間的要求較高,而且有上述字符格式的問題。其實還可以考慮PG的插件mysql_fdw,可以直接用select into的方式將數(shù)據(jù)直接插入PG中,可以省去中間導(dǎo)出的步驟。但是9.6的PG,對foreign table的語法支持不完善,不支持like的方式建表,所以對寬表,create foreign table寫起來就比較麻煩,可以考慮用腳本自動化。

另外,生產(chǎn)中往往mysql和PG不在一臺機器上,mysql_fdw拉取和插入數(shù)據(jù)的效率還有待測試。我初步的嘗試發(fā)現(xiàn),速度是很慢的,不過沒有深入調(diào)查原因,有可能是網(wǎng)絡(luò)問題,也有可能是配置問題

mysql_fdw的說明參考德哥的博客:http://blog.163.com/digoal@126/blog/static/163877040201493145214445/

總結(jié)

以上是生活随笔為你收集整理的mysql5.6最好的备份方案_Mysql 5.6迁移至PostgreSQL 9.6的实践小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。