导入数据库时如何忽略某些MySQL表?

How to ignore certain MySQL tables when importing a database?

提问人:DanielAttard 提问时间:5/24/2013 最后编辑:Jesse NicklesDanielAttard 更新时间:10/22/2023 访问量:84893

问:

我有一个大型 SQL 文件,其中包含一个数据库和大约 150 个表。我想用于导入该数据库,但是,我希望导入过程忽略或跳过几个表。导入所有表但忽略其中一些表的正确语法是什么?谢谢。mysqlimport

mysql 导入

评论

0赞 Drew 5/24/2013
我不知道这是否可能。你能创建一个.sql的备份,在文本中寻找它们并破坏它们,或者这是你要一次又一次地做的事情。你可以用CTRL-H来查找和替换REM stmt,或者在最后运行一点“从表1中删除”;“delete from table2” 排序脚本
0赞 lurker 5/24/2013
有很多需要省略的地方吗?它们是如何识别的?也许可以考虑导入整个内容,然后在您不想保留的那些上运行删除表。
0赞 DanielAttard 5/24/2013
我认为 SQL 文件中的某个表可能存在问题,因此我的导入过程未完成。您知道从命令行使用导入过程与从MySQL Workbench使用导入实用程序是否不同吗?
0赞 Jesse Nickles 8/2/2022
相关新闻: stackoverflow.com/questions/425158/...

答:

12赞 RandomSeed 5/24/2013 #1

mysqlimport不是导入 SQL 语句的正确工具。此工具旨在导入格式化的文本文件,例如 CSV。您要做的是使用 如下 命令将 sql 转储直接馈送到客户端:mysql

bash > mysql -D your_database < your_sql_dump.sql

既不提供也不提供您需要的功能。最好的机会是导入整个转储,然后删除不需要的表。mysqlmysqlimport

如果您有权访问转储来自的服务器,则可以使用 创建一个新的转储。mysqldump --ignore-table=database.table_you_dont_want1 --ignore-table=database.table_you_dont_want2 ...


查看此答案,了解跳过导入某些表的解决方法

评论

0赞 DanielAttard 5/24/2013
谢谢你的评论。我的问题似乎是,当我在MySQL Workbench中使用导入命令时,此过程有效,但仅导入大约三分之一的表,然后挂在特定表上。由于有问题的表,我无法导入所有表。
1赞 RandomSeed 5/24/2013
尝试直接从命令行导入转储。您是否遇到同样的问题?至少你可以看到一些错误消息。
1赞 Domenic D. 7/26/2013 #2

如果需要,您可以一次执行一个表:

mysqldump -p sourceDatabase tableName > tableName.sql
mysql -p -D targetDatabase < tableName.sql
160赞 Don 10/15/2014 #3

RandomSeed 接受的答案可能需要很长时间!导入表(稍后删除它)可能会非常浪费,具体取决于大小。

对于使用

mysqldump -u user -ppasswd --opt --routines DBname > DBdump.sql

我目前得到一个大约 7GB 的文件,其中 6GB 是我“不需要”在那里的日志表的数据;重新加载此文件需要几个小时。如果我需要重新加载(出于开发目的,或者如果需要实时恢复),我会这样浏览文件:

sed '/INSERT INTO `TABLE_TO_SKIP`/d' DBdump.sql > reduced.sql

并重新加载:

mysql -u user -ppasswd DBname < reduced.sql

这给了我一个完整的数据库,其中创建了“不需要的”表但为空。如果您真的根本不想要这些表,只需在加载完成后删除空表即可。

对于多个表,您可以执行如下操作:

sed '/INSERT INTO `TABLE1_TO_SKIP`/d' DBdump.sql | \
sed '/INSERT INTO `TABLE2_TO_SKIP`/d' | \
sed '/INSERT INTO `TABLE3_TO_SKIP`/d' > reduced.sql

有一个“陷阱” - 注意转储中可能包含“INSERT INTO TABLE_TO_SKIP”的过程。

评论

5赞 Castro Roy 3/27/2015
哇!!!太棒了,我刚刚将备份从 1GB 减少到 72MB,为我节省了很多时间,谢谢
23赞 Xosofox 6/23/2016
考虑该选项和 RegExp,以防您想一次性消除更多表,例如:sed -rsed -r '/INSERT INTO `(TABLE1_TO_SKIP|TABLE2_TO_SKIP)`/d' DBdump.sql > reduced.sql
3赞 res 8/22/2016
just FLY:区分大小写,通常:)TABLE_TO_SKIPtable_to_skip
4赞 gsziszi 4/9/2019
对于 Windows,请查找“SED for Windows” - 现在可以在此处找到: gnuwin32.sourceforge.net/packages/sed.htm - 并使用双引号而不是单引号作为命令
1赞 CT. 1/10/2020
请注意,如果存在,则不会使用此 SED 命令删除它们。有些人不知道,但我不会说出自己的名字-- Table structure for table <TABLE_TO_SKIP> DROP TABLE IF EXISTS <TABLE_TO_SKIP>; CREATE TABLE <TABLE_TO_SKIP> ( -- Dumping data for table <TABLE_TO_SKIP> LOCK TABLES <TABLE_TO_SKIP> WRITE;
1赞 Alexey Muravyov 5/30/2018 #4

这是我从mysql转储中排除一些表的脚本 当需要保留订单和付款数据时,我用它来恢复数据库

exclude_tables_from_dump.sh

#!/bin/bash

if [ ! -f "$1" ];
then
    echo "Usage: $0 mysql_dump.sql"
    exit
fi

declare -a TABLES=(
user
order
order_product
order_status
payments
)

CMD="cat $1"
for TBL in "${TABLES[@]}";do
    CMD+="|sed 's/DROP TABLE IF EXISTS \`${TBL}\`/# DROP TABLE IF EXIST \`${TBL}\`/g'"
    CMD+="|sed 's/CREATE TABLE \`${TBL}\`/CREATE TABLE IF NOT EXISTS \`${TBL}\`/g'"
    CMD+="|sed -r '/INSERT INTO \`${TBL}\`/d'"
    CMD+="|sed '/DELIMITER\ \;\;/,/DELIMITER\ \;/d'"
done

eval $CMD

它避免了表的 DROP 和 reCREATE 以及向此表插入数据。 此外,它还剥离了存储在 DELIMITER 之间的所有 FUNCTIONS 和 PROCEDURES;和分隔符 ;

15赞 feskr 8/23/2018 #5

对于任何处理.sql.gz文件的人;我发现以下解决方案非常有用。我们的数据库是 25GB+,我不得不删除日志表。

gzip -cd "./mydb.sql.gz" | sed -r '/INSERT INTO `(log_table_1|log_table_2|log_table_3|log_table_4)`/d' | gzip > "./mydb2.sql.gz"

感谢 Don 的回答和 Xosofox 的评论以及这篇相关文章:使用 zcat 和 sed 或 awk 编辑压缩的 .gz 文本文件

评论

0赞 Shekhar 1/29/2021
谢谢。这太棒了!
0赞 Olle Härstedt 7/6/2023
嗯,你也可以在 sed 行中使用通配符吗? 还是这样?log_table_*
0赞 feskr 7/7/2023
in 是 (linux.die.net/man/1/sed) 的缩写。因此,您应该能够使用正则表达式。-rsed -r '/INSERT INTO.../d'--regexp-extended
0赞 Zoran 9/8/2018 #6

我不会在生产中使用它,但是如果我必须快速导入一些备份,其中包含许多较小的表和一个可能需要数小时才能导入的大怪物表,我很可能会“grep -v unwanted_table_name原始的.sql >减少.sql

然后 mysql -f < 减少.sql

评论

0赞 Don 6/18/2020
您可能需要注意以下情况:您的unwanted_table_name是“SALES”,但您有另一个名为“BIGSALES”的表,或者可能是一个名为 .你的答案可能会导致一个痛苦的世界。另外,如果你要走这条路,fgrep 肯定会比 grep 快得多吗?another_table_SALES_fk
5赞 dGo 10/26/2018 #7

有点老了,但想它可能还是会派上用场......

我喜欢@Don的答案(https://stackoverflow.com/a/26379517/1446005),但发现你必须先写到另一个文件,这很烦人......
在我的特殊情况下,这将花费太多时间和磁盘空间

所以我写了一个小 bash 脚本:

#!/bin/bash

tables=(table1_to_skip table2_to_skip ... tableN_to_skip)


tableString=$(printf "|%s" "${tables[@]}")
trimmed=${tableString:1}
grepExp="INSERT INTO \`($trimmed)\`"

zcat $1 | grep -vE "$grepExp" | mysql -uroot -p

这不会生成新的 SQL 脚本,而是将其直接管道传递到数据库
,它确实会创建表,只是不导入数据(这是我在大型日志表中遇到的问题)

2赞 DUzun 7/11/2019 #8

除非您在转储期间忽略了这些表,否则在将数据传递给客户端之前,必须使用一些脚本或工具来筛选出您不想从转储文件中导入的数据。mysqldump --ignore-table=database.unwanted_tablemysql

下面是一个 bash/sh 函数,它将动态地(通过管道)从 SQL 转储中排除不需要的表:

# Accepts one argument, the list of tables to exclude (case-insensitive).
# Eg. filt_exclude '%session% action_log %_cache'
filt_exclude() {
    local excl_tns;
    if [ -n "$1" ]; then
        # trim & replace /[,;\s]+/ with '|' & replace '%' with '[^`]*'
        excl_tns=$(echo "$1" | sed -r 's/^[[:space:]]*//g; s/[[:space:]]*$//g; s/[[:space:]]+/|/g; s/[,;]+/|/g; s/%/[^\`]\*/g');

        grep -viE "(^INSERT INTO \`($excl_tns)\`)|(^DROP TABLE (IF EXISTS )?\`($excl_tns)\`)|^LOCK TABLES \`($excl_tns)\` WRITE" | \
        sed 's/^CREATE TABLE `/CREATE TABLE IF NOT EXISTS `/g'        
    else
        cat
    fi
}

假设您创建了一个转储,如下所示:

MYSQL_PWD="my-pass" mysqldump -u user --hex-blob db_name | \
pigz -9 > dump.sql.gz

并希望在导入之前排除一些不需要的表:

pigz -dckq dump.sql.gz | \
filt_exclude '%session% action_log %_cache' | \
MYSQL_PWD="my-pass" mysql -u user db_name

或者,您可以在导入数据库之前通过管道进入文件或任何其他工具。

1赞 Julesezaar 3/10/2023 #9

除了本主题中的重要答案之外,可能是您的 .sql 文件没有每行都包含以下内容的 INSERTS:

INSERT INTO `log`

但它们实际上是这样插入的:

LOCK TABLES `log` WRITE;

INSERT INTO `log` (`id`, `data`)
VALUES
  (1,'The log content'),
  (2,'The log content'),
  (3,'The log content'),
  (4,'The log content')
    
UNLOCK TABLES;

您需要排除 and next 之间的所有内容LOCK TABLES `log` WRITE;UNLOCK TABLES;

gzip -dc "$1" | sed \
-e '/LOCK TABLES `log` WRITE;/,/^UNLOCK TABLES/d;' \
-e '/LOCK TABLES `some_other_table` WRITE;/,/^UNLOCK TABLES/d;' \
| gzip > reduced_$(date '+%F_%T').sql.gz

把它放在你电脑上某个地方的reduce_db.sh里,每次你需要它时,你都会这样执行它

bash /folder/to/reduce_db.sh /path/to/big_db_file.sql.gz

很高兴知道,仅排除数据库中没有其他数据依赖的数据。否则,您的缩减数据库最终会不一致。

0赞 Martin Rüegg 10/22/2023 #10

根据其他答案,我创建了一个 BASH 脚本:
https://gist.github.com/martin-rueegg/e247d99cc7402a4f1456c059c5d050ac

例子
  • 显示将要过滤的内容:

    $ mysql_filter_tables --show "log"
    $ mysql_filter_tables --show "%session%" "action_log" "%_cache"
    $ mysql_filter_tables --show -- "-h"  # in case your table name is "-h"
    
  • 纯SQL文件的用法:

    $ mysql_filter_tables "log" <big.sql >clean.sql
    $ cat big.sql | mysql_filter_tables "log" >clean.sql
    
  • 将普通 SQL 转储导入 mysql:

    $ MYSQL_PWD=secret mysql_filter_tables -i big.sql "%_cache" | mysql -u user -D database
    
  • 如果源被压缩:

    $ mysql_filter_tables -i big.sql.zip --unzip -o clean.sql "%session%" "%_cache"
    $ mysql_filter_tables -i big.sql.gz --gunzip -o clean.sql "%session%" "%_cache"
    
更多选项
Command Options:
  --show
    show generated sed command, rather than executing it

  -i | --input file
    read from file, rather than standard input

  -o | --output file
    write result to file, rather than standard output

  -f | --force
    overwrite output file, if exists

  -u | -ui | --unzip
    unzip input stream. Use with -i to read from file

  -z | -zo | --zip
    zip ouput stream. Use with -o to write to file

  -g | -gi | --gunzip
    gunzip input stream. Use with -i to read from file

  -G | -go | --gzip
    gzip ouput stream. Use with -o to write to file

Info Options:
  -h|--help       show help
  -V|--version    show version
  -1|--one-line   show a one-liner that can be easily used in other scripts.
                  (Does not support any info options, except -V)
  --copyright     show copyright, license, and credits
  --credits       show copyright, license, and credits
  --license       show copyright, license, and credits
安装
  • 从 github.com 下载文件

    $ wget https://gist.github.com/martin-rueegg/e247d99cc7402a4f1456c059c5d050ac/raw/mysql_filter_tables.sh
    
  • 为了您自己的安全,检查文件

  • 获取文件,然后使用 shell 中的函数,或者......

    $ source mysql_filter_tables.sh
    $ mysql_filter_tables --help
    
  • ...将文件标记为可执行文件并将其用作脚本

    $ chmod a+x mysql_filter_tables.sh
    $ ./mysql_filter_tables.sh --help
    
依赖
  • bash
  • sed,cat
  • zip,unzip
  • gzip,zcat

学分