利用mysqldump导出数据库的子集
一、引言
假如:
- 你有一个非常大的正式数据库,和一个空的测试数据库
- 需要把正式数据库中的部分数据导到测试数据库中用来测试,同时,
- 希望导入的数据尽可能的保持一致性、完备性
比如,有一个商城的数据库,你希望导出其中的部分数据到测试数据库中,导入的两个主要依据是:
- 用户表
:购买了商品的部分用户和没有购买商品的部分用户user
- 商品表
:部分已经有过购买的商品和部分没人购买的商品goods
其他表(如订单
order
、浏览历史
view_history
则依据已经导出的
user
表和
goods
表导出,而诸如文章
articles
这类属于系统的表则可以独立地部分导出,有些系统配置的表(如
shop_config
)则需要全部导出。另外一些表你只希望导出空表,因为担心其中的记录会影响测试。
通过使用
mysqldump
工具的一些选项,通过管道配合
mysql
,利用
shell
脚本把这些命令组织起来,可以做到。
mysqldump
相关选项:
-
-w
选项
指定导出的条件,相当于查询中指定的
语句WHERE
-
-d`选项
不导出数据,只导出表的定义。用于导出空表
-
-t
选项
与
-d
选项相反,只导出数据,不导出表的定义。用来追加记录到已经存在的表。
mysqldump默认会同时导出表的定义和数据
其它:
-
的msyql
-e
选项
用来执行一个sql语句组成的字符串,必须要用双引号包含起来
- 管道操作符
用来把前一个命令的输出作为后一个命令的输入|
二、实现
导入数据的源数据库和目的数据库相关配置如下(已经写在shell脚本中):
#!/bin/bash
REMOTE_DBHOST=a.remote.com
REMOTE_DBNAME=shop
REMOTE_DBUSER=root
REMOTE_DBPASS=root
LOCAL_DBHOST=localhost
LOCAL_DBNAME=shop
LOCAL_DBUSER=root
LOCAL_DBPASS=root
REMOTE_ARGS=" -h${REMOTE_DBHOST} -u${REMOTE_DBUSER} -p${REMOTE_DBPASS} ${REMOTE_DBNAME}"
LOCAL_ARGS=" -h${LOCAL_DBHOST} -u${LOCAL_DBUSER} -p${LOCAL_DBPASS} ${LOCAL_DBNAME}"
第一步,筛选相关的用户id。
function selectUserId() {
echo "select users ..."
# 创建一个临时表来存储用户id
mysql ${REMOTE_ARGS} -e "DROP TABLE IF EXISTS tmp_user_ids; CREATE TABLE tmp_user_ids(id INT NOT NULL PRIMARY KEY);"
# 选择购买了商品的部分用户,最多导入100个哈
mysql ${REMOTE_ARGS} -e "INSERT INTO tmp_user_ids SELECT DISTINCT user_id FROM `order` WHERE `status`= LIMIT "
# 选择没有购买商品的部分用户,最多20个
mysql ${REMOTE_ARGS} -e "INSERT INTO tmp_user_ids SELECT id FROM user WHERE id NOT IN (SELECT user_id FROM `order`) LIMIT "
}
第二步,导入用户表 user
以及用户的地址表 address
。
user
address
function dumpUserTable() {
mysqldump ${REMOTE_ARGS} user -w 'id IN (SELECT id FROM tmp_user_ids)' | mysql ${LOCAL_ARGS}
mysqldump ${REMOTE_ARGS} address -w 'user_id IN (SELECT id FROM tmp_user_ids)' | mysql ${LOCAL_ARGS}
}
第三步,导入用户的订单表 order
以及订单商品表 order_goods
。
order
order_goods
function dumpOrderTable() {
mysqldump ${REMOTE_ARGS} order -w 'user_id IN (SELECT id FROM tmp_user_ids)' | mysql ${LOCAL_ARGS}
# order的视图
mysql ${REMOTE_ARGS} -e "CREATE VIEW view_order_tmp as SELECT * FROM `order` WHERE user_id IN (SELECT id FROM tmp_user_ids)"
mysqldump ${REMOTE_ARGS} order_goods -w 'order_id IN (SELECT id view_order_tmp)' | mysql
# order_goods的视图
mysql ${REMOTE_ARGS} -e "CREATE VIEW view_order_goods_tmp as SELECT * FROM `order_goods` WHERE order_id IN (SELECT id view_order_tmp)"
}
第四步,导入商品表 goods
。
goods
function dumpGoodsTable() {
# 导出出售过的商品
mysqldump ${REMOTE_ARGS} goods -w 'id IN (SELECT goods_id FROM view_order_goods_tmp)' | mysql ${LOCAL_ARGS}
# 导出未出售过的商品,限10个。因为追加,所以用-t选项
mysqldump ${REMOTE_ARGS} goods -t -w 'id NOT IN (SELECT goods_id FROM view_order_goods_tmp) LIMIT 10' | mysql ${LOCAL_ARGS}
# 未出售过商品的视图
mysql {$REMOTE_ARGS} -e "CREATE VIEW view_goods_tmp AS (SELECT * FROM goods WHERE id NOT IN (SELECT goods_id FROM view_order_goods_tmp) LIMIT 10)"
# 导出商品的图片
mysqldump ${REMOTE_ARGS} goods_images -w 'goods_id IN (SELECT goods_id FROM view_order_goods_tmp)' | mysql ${LOCAL_ARGS}
mysqldump ${REMOTE_ARGS} goods_images -t -w 'goods_id IN (SELECT goods_id FROM view_goods_tmp)' | mysql ${LOCAL_ARGS}
}
第五步,导入其它表。
function dumpOtherTables() {
# 导出10篇文章
mysqldump ${REMOTE_ARGS} articles -w '1 LIMIT 50' | mysql ${LOCAL_ARGS}
# 商城配置,全部导出
mysqldump ${REMOTE_ARGS} shop_config | mysql ${LOCAL_ARGS}
# 评论,导出空表
mysqldump ${REMOTE_ARGS} comment -d | mysql ${LOCAL_ARGS}
}
第六步,清除远程服务器上的临时表和视图
function cleanTmpTableAndView() {
mysql ${REMOTE_ARGS} -e "DROP TABLE tmp_user_ids;DROP VIEW view_goods_tmp;DROP VIEW view_order_goods_tmp;DROP VIEW view_order_tmp"
}
最后,把以上函数组织起来,运行
function main() {
selectUsers;
dumpUserTable;
dumpOrderTable;
dumpGoodsTable;
dumpOtherTables;
cleanTmpTableAndView;
}
# 运行
main
注意:
- 编写命令时必须清楚到底是命令针对的是远程的数据库还是在本地的数据库中操作,以免把本地数据库中的表与远程数据库中的表混在一起操作。
- 若要避免过多的嵌套SELECT查询,可以在源数据库中先建立一个视图来辅助
三、总结
mysqldump
还有其他很有用处的选项,可用
mysqldump --help
打印出帮助研究下。
说明:本篇文章的例子是根据真实用例改编而来的,真实的用例因为与工作相关,当然不可能原原本本的搬出来哈。真实的用例比这个要简单,不需要创建视图,不过表比较多,相同类型操作的表写在一个文件里,然后逐行读取操作。