如何将 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 严重削弱了我大型数据表的导入时间。不过,我看不出这有什么帮助。即使设置为TRUEINSERT 语句也都在一行上,因此您可以安全地将转储文件拆分为 n 行,而您唯一会丢失的是切换到导入更多数据时的锁下一个文件中的表(您可以通过简单地cating 重新建立它)。【参考方案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 的输出拆分为较小的文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将列表拆分为较小的列表?

使用 PHP 将大型 KML 文件拆分为较小的文件

使用 Python 按行号将大文本文件拆分为较小的文本文件

将“大”表拆分为较小的表

c#如何将2D数组拆分为较小的2D数组(块)列表?

按列名称将数据框拆分为较小的数据框