如何将 mysqldump 的输出拆分为较小的文件?
Posted
技术标签:
【中文标题】如何将 mysqldump 的输出拆分为较小的文件?【英文标题】:How do I split the output from mysqldump into smaller files? 【发布时间】:2010-09-13 03:41:57 【问题描述】:我需要将整个表从一个 mysql 数据库移动到另一个。我没有对第二个的完全访问权限,只有 phpMyAdmin 访问权限。我只能上传(压缩)小于 2MB 的 sql 文件。但是第一个数据库表的 mysqldump 的压缩输出大于 10MB。
有没有办法将 mysqldump 的输出拆分成更小的文件?我不能使用 split(1),因为我不能 cat(1) 将文件返回到远程服务器上。
或者还有其他我错过的解决方案吗?
编辑
第一个发布者建议的 mysqldump 的 --extended-insert=FALSE 选项会生成一个 .sql 文件,然后可以将其拆分为可导入的文件,前提是使用合适的 --lines 选项调用 split(1)。通过反复试验,我发现 bzip2 将 .sql 文件压缩了 20 倍,所以我需要弄清楚有多少行 sql 代码大致对应于 40MB。
【问题讨论】:
看看这个Q,如果你搜索如何split a large postgresql dump into smaller files 【参考方案1】:此 bash 脚本将一个数据库的转储文件拆分为每个表的单独文件,并以 csplit 命名并相应地命名它们:
#!/bin/bash
####
# Split MySQL dump SQL file into one file per table
# based on https://gist.github.com/jasny/1608062
####
#adjust this to your case:
START="/-- Table structure for table/"
# or
#START="/DROP TABLE IF EXISTS/"
if [ $# -lt 1 ] || [[ $1 == "--help" ]] || [[ $1 == "-h" ]] ; then
echo "USAGE: extract all tables:"
echo " $0 DUMP_FILE"
echo "extract one table:"
echo " $0 DUMP_FILE [TABLE]"
exit
fi
if [ $# -ge 2 ] ; then
#extract one table $2
csplit -s -ftable $1 "/-- Table structure for table/" "%-- Table structure for table \`$2\`%" "/-- Table structure for table/" "%40103 SET TIME_ZONE=@OLD_TIME_ZONE%1"
else
#extract all tables
csplit -s -ftable $1 "$START" *
fi
[ $? -eq 0 ] || exit
mv table00 head
FILE=`ls -1 table* | tail -n 1`
if [ $# -ge 2 ] ; then
# cut off all other tables
mv $FILE foot
else
# cut off the end of each file
csplit -b '%d' -s -f$FILE $FILE "/40103 SET TIME_ZONE=@OLD_TIME_ZONE/" *
mv $FILE1 foot
fi
for FILE in `ls -1 table*`; do
NAME=`head -n1 $FILE | cut -d$'\x60' -f2`
cat head $FILE foot > "$NAME.sql"
done
rm head foot table*
基于https://gist.github.com/jasny/1608062 和https://***.com/a/16840625/1069083
【讨论】:
需要注意的是,Mac 上的 csplit 不适用于此脚本,因为它不支持 * 语法。需要在 Linux 中运行。 在 FreeBSD 上相同。但是您可以在那里安装 sysutils/coreutils 端口或软件包以获取 GNU 实用程序并改用 gcsplit。 哦,伙计,我不能比你足够的这个脚本。我有一个 3TB 的 mysqlDump 失败了两次,现在我可以逐表导入它,并在它失败时从我离开的地方继续。很多爱送你的方式。 最好。当数据库位于 localhost 以外的其他服务器中时,mysqldump 不能与 --tab 选项一起使用。因此,您可以转储所有数据库,将输出重定向到一个文件,然后使用该脚本拆分表!但我正在寻找一种作为 --tab 选项的方法:将结构拆分为 sql 文件,将数据拆分为 txt 制表符分隔的数据。任何魔术脚本,或者我会创建另一个拆分和转换脚本?【参考方案2】:首先转储架构(它肯定适合 2Mb,不是吗?)
mysqldump -d --all-databases
并恢复它。
之后仅在单独的插入语句中转储数据,因此您可以拆分文件并恢复它们,而无需在远程服务器上连接它们
mysqldump --all-databases --extended-insert=FALSE --no-create-info=TRUE
【讨论】:
我正在寻找一种方法来为插入的每一行启用一个 INSERT 语句,而不是一个包含许多元组的大型语句或使用 VALUES 的每一行。--extended-insert=FALSE
标志是我所需要的。谢谢!
创建表:mysqldump mydatabase mytable -d > mytable-create.sql
数据:mysqldump mydatabase mytable --extended-insert=FALSE --no-create-info=TRUE > mytable-data.sql
然后将其拆分为一系列任意长度的文件:split mytable-data.sql -l10000
现在您可以先导入创建 SQL。然后每个表的长度为 10,000。默认情况下,文件将命名为 xaa、xab、xac...)。通过mysql mydatabase < xaa
等对它们进行重要说明。
设置 --extended-insert=FALSE
严重削弱了我大型数据表的导入时间。不过,我看不出这有什么帮助。即使设置为TRUE
,INSERT
语句也都在一行上,因此您可以安全地将转储文件拆分为 n 行,而您唯一会丢失的是切换到导入更多数据时的锁下一个文件中的表(您可以通过简单地cat
ing 重新建立它)。【参考方案3】:
有这个出色的 mysqldumpsplitter 脚本,在从 mysqldump 中提取时提供了大量选项。
我会复制这里的食谱来选择你的案例:
1) 从mysqldump中提取单个数据库:
sh mysqldumpsplitter.sh --source filename --extract DB --match_str database-name
以上命令将从指定的数据库中创建指定数据库的 sql "filename" sql 文件并以压缩格式存储到 数据库名称.sql.gz。
2) 从mysqldump中提取单个表:
sh mysqldumpsplitter.sh --source filename --extract TABLE --match_str table-name
上面的命令将从指定的表中为指定的表创建 sql "filename" mysqldump 文件并以压缩格式存储到 数据库名称.sql.gz。
3) 从mysqldump中提取匹配正则表达式的表:
sh mysqldumpsplitter.sh --source filename --extract REGEXP --match_str regular-expression
以上命令将为匹配指定正则的表创建 sqls 来自指定“文件名”mysqldump 文件的表达式并将其存储在 压缩格式为单个表名.sql.gz。
4) 从mysqldump中提取所有数据库:
sh mysqldumpsplitter.sh --source filename --extract ALLDBS
以上命令将从指定的“文件名”中提取所有数据库 mysqldump 文件并将其以压缩格式存储到个人 数据库名称.sql.gz。
5) 从 mysqldump 中提取所有表:
sh mysqldumpsplitter.sh --source filename --extract ALLTABLES
上述命令将从指定的“文件名”中提取所有表 mysqldump 文件并将其以压缩格式存储到个人 表名.sql.gz。
6) 从 mysqldump 中提取表列表:
sh mysqldumpsplitter.sh --source filename --extract REGEXP --match_str '(table1|table2|table3)'
上述命令将从指定的“文件名”中提取表 mysqldump 文件并将它们以压缩格式存储到个人 表名.sql.gz。
7) 从压缩的 mysqldump 中提取数据库:
sh mysqldumpsplitter.sh --source filename.sql.gz --extract DB --match_str 'dbname' --decompression gzip
以上命令将使用 gzip 解压 filename.sql.gz,解压 来自“filename.sql.gz”的名为“dbname”的数据库并将其存储为 out/dbname.sql.gz
8) 从未压缩的压缩 mysqldump 中提取数据库 格式:
sh mysqldumpsplitter.sh --source filename.sql.gz --extract DB --match_str 'dbname' --decompression gzip --compression none
以上命令将使用 gzip 解压 filename.sql.gz 并解压 来自“filename.sql.gz”的名为“dbname”的数据库并将其存储为纯 sql out/dbname.sql
9) 从不同文件夹的mysqldump中提取所有表:
sh mysqldumpsplitter.sh --source filename --extract ALLTABLES --output_dir /path/to/extracts/
上述命令将从指定的“文件名”中提取所有表 mysqldump 文件并以压缩格式将表提取到单个 文件,table-name.sql.gz 存储在 /path/to/extracts/ 下。剧本 如果不存在,将创建文件夹 /path/to/extracts/。
10) 以完全转储的方式从一个数据库中提取一张或多张表:
假设您有一个包含多个数据库的完整转储,并且您希望 从一个数据库中提取几张表。
提取单个数据库:
sh mysqldumpsplitter.sh --source filename --extract DB --match_str DBNAME --compression none
提取所有表
sh mysqldumpsplitter.sh --source out/DBNAME.sql --extract REGEXP --match_str "(tbl1|tbl2)"
尽管我们可以使用另一个选项在单个命令中执行此操作,如下所示:
sh mysqldumpsplitter.sh --source filename --extract DBTABLE --match_str "DBNAME.(tbl1|tbl2)" --compression none
上面的命令将从 DBNAME 数据库中提取 tbl1 和 tbl2 当前目录“out”文件夹下的sql格式。
您可以按如下方式提取单个表:
sh mysqldumpsplitter.sh --source filename --extract DBTABLE --match_str "DBNAME.(tbl1)" --compression none
11) 从特定数据库中提取所有表:
mysqldumpsplitter.sh --source filename --extract DBTABLE --match_str "DBNAME.*" --compression none
以上命令将在 sql 中从 DBNAME 数据库中提取所有表 格式化并将其存储在“out”目录下。
12) 列出mysqldump文件的内容
mysqldumpsplitter.sh --source filename --desc
以上命令将列出转储文件中的数据库和表。
您可以稍后选择加载文件:zcat filename.sql.gz | mysql -uUSER -p -hHOSTNAME
此外,一旦您提取了您认为更大的单个表,您可以使用带有行数的 linux split 命令进一步拆分转储。
split -l 10000 filename.sql
也就是说,如果这是您的需要(更频繁地出现),您可以考虑使用mydumper,它实际上会创建您不需要拆分的单独转储!
【讨论】:
我必须在你的 bash 脚本上补充你。我有一个巨大的数据库备份,我花了大约 60 个小时来拆分数据库。我担心你的脚本可能会损坏,但它就像一个魅力。谢谢,继续努力。 这太有帮助了!感谢发帖【参考方案4】:您说您无权访问第二台服务器。但是,如果您对表所在的第一台服务器具有 shell 访问权限,则可以按表拆分转储:
for T in `mysql -N -B -e 'show tables from dbname'`; \
do echo $T; \
mysqldump [connecting_options] dbname $T \
| gzip -c > dbname_$T.dump.gz ; \
done
这将为每个表创建一个 gzip 文件。
另一种将 mysqldump 的输出拆分为单独文件的方法是使用 --tab 选项。
mysqldump [connecting options] --tab=directory_name dbname
其中 directory_name 是空目录的名称。 此命令为每个表创建一个 .sql 文件,其中包含 CREATE TABLE 语句,以及一个 .txt 文件,其中包含要使用 LOAD DATA INFILE 恢复的数据。不过,我不确定 phpMyAdmin 是否可以根据您的特定限制处理这些文件。
【讨论】:
虽然这可能不能直接满足 OP 的需求,但它是一种将单个表放入自己的文件中的好方法......对于 grep 等。 如果在此脚本运行时写入任何表,备份将处于不一致状态。【参考方案5】:回复较晚,但正在寻找相同的解决方案,并从以下网站发现以下代码:
for I in $(mysql -e 'show databases' -s --skip-column-names); do mysqldump $I | gzip > "$I.sql.gz"; done
http://www.commandlinefu.com/commands/view/2916/backup-all-mysql-databases-to-individual-files
【讨论】:
【参考方案6】:我最近创建了sqlsplit.com。试试看。
【讨论】:
您的应用运行良好,但您如何处理上传的文件? @DaniëlTulp 什么都没有。上传的文件在拆分并发送给用户后会立即被删除。 github.com/sqlsplit/sqlsplit/blob/master/public/index.php#L38 可能会添加一些关于此的隐私声明(也符合 GDPR,感谢应用程序,用它来恢复生产网站 @DaniëlTulp 刚刚添加了隐私对话框。【参考方案7】:我编写了一个新版本的 SQLDumpSplitter,这一次使用了一个适当的解析器,允许像 INSERT 之类的具有许多值的好东西被分割到文件中,它现在是多平台的:https://philiplb.de/sqldumpsplitter3/
【讨论】:
【参考方案8】:您不需要通过 ssh 访问您的任何一个服务器。只是一个 mysql[dump] 客户端就可以了。 使用 mysql[dump],您可以转储数据库并再次导入。
在您的 PC 中,您可以执行以下操作:
$ mysqldump -u originaluser -poriginalpassword -h originalhost originaldatabase | mysql -u newuser -pnewpassword -h newhost newdatabase
你就完成了。 :-)
希望对你有帮助
【讨论】:
【参考方案9】:您可以通过 AWK 拆分现有文件。它非常快速和简单
让我们按“表”拆分表转储:
cat dump.sql | awk 'BEGIN output = "comments";
$data ~ /^CREATE TABLE/ close(output); output = substr($3,2,length($3)-2);
print $data >> output ';
或者您可以通过“数据库”拆分转储
cat backup.sql | awk 'BEGIN output="comments"; $data ~ /Current Database/ close(output);output=$4; print $data>>output';
【讨论】:
【参考方案10】:您可以通过运行 mysqldump database table1 table2 ... tableN
使用 mysqldump 转储单个表
如果没有一个表太大,那就足够了。否则,您将不得不开始拆分较大表中的数据。
【讨论】:
【参考方案11】:我会推荐实用程序 bigdump,您可以在此处获取它。 http://www.ozerov.de/bigdump.php 这会错开转储的执行,尽可能接近您的极限,一次执行整行。
【讨论】:
【参考方案12】:我编写了一个 Python 脚本来将单个大型 sql 转储文件拆分为单独的文件,每个 CREATE TABLE 语句一个。它将文件写入您指定的新文件夹。如果未指定输出文件夹,则会在同一目录中创建一个与转储文件同名的新文件夹。它逐行运行,无需先将文件写入内存,因此非常适合大文件。
https://github.com/kloddant/split_sql_dump_file
import sys, re, os
if sys.version_info[0] < 3:
raise Exception("""Must be using Python 3. Try running "C:\\Program Files (x86)\\Python37-32\\python.exe" split_sql_dump_file.py""")
sqldump_path = input("Enter the path to the sql dump file: ")
if not os.path.exists(sqldump_path):
raise Exception("Invalid sql dump path. sqldump_path does not exist.".format(sqldump_path=sqldump_path))
output_folder_path = input("Enter the path to the output folder: ") or sqldump_path.rstrip('.sql')
if not os.path.exists(output_folder_path):
os.makedirs(output_folder_path)
table_name = None
output_file_path = None
smallfile = None
with open(sqldump_path, 'rb') as bigfile:
for line_number, line in enumerate(bigfile):
line_string = line.decode("utf-8")
if 'CREATE TABLE' in line_string.upper():
match = re.match(r"^CREATE TABLE (?:IF NOT EXISTS )?`(?P<table>\w+)` \($", line_string)
if match:
table_name = match.group('table')
print(table_name)
output_file_path = "output_folder_path/table_name.sql".format(output_folder_path=output_folder_path.rstrip('/'), table_name=table_name)
if smallfile:
smallfile.close()
smallfile = open(output_file_path, 'wb')
if not table_name:
continue
smallfile.write(line)
smallfile.close()
【讨论】:
【参考方案13】:尝试 csplit(1) 根据正则表达式将输出切割成单个表(我认为匹配表边界)。
【讨论】:
【参考方案14】:这个script 应该这样做:
#!/bin/sh
#edit these
USER=""
PASSWORD=""
MYSQLDIR="/path/to/backupdir"
MYSQLDUMP="/usr/bin/mysqldump"
MYSQL="/usr/bin/mysql"
echo - Dumping tables for each DB
databases=`$MYSQL --user=$USER --password=$PASSWORD -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema)"`
for db in $databases; do
echo - Creating "$db" DB
mkdir $MYSQLDIR/$db
chmod -R 777 $MYSQLDIR/$db
for tb in `$MYSQL --user=$USER --password=$PASSWORD -N -B -e "use $db ;show tables"`
do
echo -- Creating table $tb
$MYSQLDUMP --opt --delayed-insert --insert-ignore --user=$USER --password=$PASSWORD $db $tb | bzip2 -c > $MYSQLDIR/$db/$tb.sql.bz2
done
echo
done
【讨论】:
【参考方案15】:查看 SQLDumpSplitter 2,我只是使用它成功拆分了 40MB 转储。您可以通过以下链接获取:
sqldumpsplitter.com
希望对您有所帮助。
【讨论】:
SQLDumpSplitter2 最多只能处理 2 GB 的文件(我认为它使用 32 位有符号整数作为文件大小)。修改这个或为 64 位编译原始源代码可能会很棒,但我担心源代码可能会丢失。否则它是一个很好的工具。但是分割 SQL 文件的许多问题始于 2 GB 左右。 您好,我只是想让您知道该程序现在可以重写:philiplb.de/sqldumpsplitter3【参考方案16】:我创建了 MySQLDumpSplitter.java,与 bash 脚本不同,它可以在 Windows 上运行。它是 可在此处获取https://github.com/Verace/MySQLDumpSplitter。
【讨论】:
【参考方案17】:澄清@Vérace 的回答:
我特别喜欢交互方式;您可以在 Eclipse 中拆分一个大文件。我已经在 Windows 中成功尝试了一个 105GB 的文件:
只需将 MySQLDumpSplitter 库添加到您的项目中: http://dl.bintray.com/verace/MySQLDumpSplitter/jar/
关于如何导入的快速说明:
- In Eclipse, Right click on your project --> Import
- Select "File System" and then "Next"
- Browse the path of the jar file and press "Ok"
- Select (thick) the "MySQLDumpSplitter.jar" file and then "Finish"
- It will be added to your project and shown in the project folder in Package Explorer in Eclipse
- Double click on the jar file in Eclipse (in Package Explorer)
- The "MySQL Dump file splitter" window opens which you can specify the address of your dump file and proceed with split.
【讨论】:
【参考方案18】:试试这个:https://github.com/shenli/mysqldump-hugetable 它将数据转储到许多小文件中。每个文件包含少于或等于 MAX_RECORDS 个记录。您可以在 env.sh 中设置此参数。
【讨论】:
以上是关于如何将 mysqldump 的输出拆分为较小的文件?的主要内容,如果未能解决你的问题,请参考以下文章