引言

在软件开发和系统管理中,导入和导出数据库是日常的核心任务。无论是为了进行数据备份、灾难恢复、环境复制,还是将数据迁移到新的服务器,数据转储文件都扮演着关键角色。本教程将深入探讨如何利用命令行工具 mysqldump 和 mysql,在 MySQL 或 MariaDB 环境中高效地执行这些操作。我们将涵盖从完整数据库的导出与导入,到特定表的处理,再到用户权限的迁移,以及针对大型 SQL 文件的优化策略。

核心要点速览:

mysqldump 是创建逻辑备份的标准工具,它将数据库的结构(schema)和数据导出为 .sql 文本文件,便于跨系统传输和恢复。

使用 mysql 客户端可以将 mysqldump 生成的转储文件导入到新的或现有数据库中。在导入前,请务必确保目标数据库已经创建。

选择性导出表:可以通过在 mysqldump 命令后明确指定表名,只导出数据库中的特定表。

用户账户和权限需要单独迁移,因为它们存储在 mysql 系统数据库中。可以通过导出相关的授权表或生成 GRANT 语句来实现。

压缩导出(例如配合 gzip)可以显著节省存储空间并加快数据传输速度,导入时也支持直接解压缩。

对于大型 InnoDB 数据库,使用 mysqldump 的 --single-transaction 和 --quick 选项可以创建一致的、非阻塞的快照,并有效减少内存消耗。

处理超大型 SQL 文件时,可以使用 split 命令将其拆分为更小的文件块,以避免导入过程中可能出现的超时或内存问题。

通过 mysqldump 的 --add-drop-table 标志可以避免导入时常见的“表已存在”(“Table already exists”)错误。在执行任何关键导入操作前,务必仔细检查或根据目标环境修改转储文件。

前置条件

要成功导入或导出 MySQL 或 MariaDB 数据库,您需要满足以下条件:

一台配置了非 root 用户的虚拟机或服务器,并授予 sudo 权限。

已安装并运行 MySQL 或 MariaDB 数据库服务。

在数据库服务器中已创建一个示例数据库用于练习(可选,但推荐)。

数据库的整体导出与导入

无论是进行备份还是环境复制,整体导出和导入数据库是最常见的操作。

导出 MySQL 或 MariaDB 数据库

使用 mysqldump 工具将整个数据库导出为一个 SQL 文本文件。

mysqldump -u username -p database_name > data-dump.sql

username:用于登录数据库的用户名(通常是 root 或拥有相应权限的用户)。

database_name:您希望导出的数据库的名称。

data-dump.sql:用于存储导出内容的 SQL 文件名。

此命令执行时,终端通常不会有输出。您可以通过查看文件内容的前几行来确认其是否为有效的 SQL 转储文件:

head -n 5 data-dump.sql

文件顶部的内容应类似于:

-- MySQL dump 10.13 Distrib 5.7.16, for Linux (x86_64)

--

-- Host: localhost Database: database_name

-- ------------------------------------------------------

-- Server version 5.7.16-0ubuntu0.16.04.1

导入 MySQL 或 MariaDB 数据库

要导入现有的数据库转储文件,通常需要先创建一个新的数据库。

登录 MySQL shell:

mysql -u root -p

输入密码后进入 MySQL 命令行界面。

创建新的数据库:

例如,创建一个名为 new_database 的数据库。

CREATE DATABASE new_database;

退出 MySQL shell:

按下 CTRL+D 或输入 exit;。

从命令行导入转储文件:

mysql -u username -p new_database < data-dump.sql

导入成功后,命令行通常也不会有任何输出。您可以通过再次登录 MySQL shell,然后执行 USE new_database; 和 SHOW TABLES; 命令来验证数据是否已成功导入。

特定表的导出与导入

有时您可能只需要导出或导入数据库中的特定表,这在处理大型数据库、进行局部调试或仅迁移部分数据时非常有用。

导出特定表

在 mysqldump 命令的数据库名称后指定要导出的表名,用空格分隔:

mysqldump -u username -p database_name table1 table2 > selected-tables.sql

示例:

导出 store 数据库中的 users 表和 orders 表:

mysqldump -u root -p store users orders > users-orders.sql

您可以再次使用 head -n 10 users-orders.sql 命令来确认文件内容。

导入特定表

导入特定表的语法与导入完整数据库类似,但需要确保目标数据库已存在:

mysql -u username -p target_database < selected-tables.sql

示例:

将 users-orders.sql 文件导入到 test_store 数据库中:

mysql -u root -p test_store < users-orders.sql

此操作将只在 test_store 数据库中重新创建并填充 users 和 orders 表。如果这些表已经存在,它们将被转储文件中的数据覆盖(除非转储文件配置了跳过创建表的选项)。

用户权限的导出与迁移

在迁移数据库时,仅仅复制数据是不够的,还需要确保用户账户及其关联的权限也一同迁移。这些信息通常存储在 mysql 系统数据库中,mysqldump 默认不会导出这些内部数据库。

迁移用户账户及其权限主要有两种方法:

方法一:直接转储 mysql 系统数据库中的授权表

此方法直接复制了存储用户账户和权限的关键内部表,适用于在相似的 MySQL/MariaDB 服务器版本之间进行迁移。

导出用户账户和权限相关的表:

mysqldump -u root -p mysql user db tables_priv columns_priv procs_priv > users_and_privileges.sql

重要提示:切勿尝试转储整个 mysql 数据库,因为它包含了可能与目标服务器不兼容的内部元数据。这里我们只选择性地导出与用户、数据库权限、表权限、列权限和存储过程权限相关的表。

在目标服务器上导入这些授权表:

mysql -u root -p mysql < users_and_privileges.sql

重新加载权限:

导入完成后,必须手动重新加载权限表,使更改生效。

mysql -u root -p -e "FLUSH PRIVILEGES;"

或者登录 MySQL shell 执行:

FLUSH PRIVILEGES;

方法二:生成 GRANT 语句(推荐用于可移植性)

此方法更加灵活,尤其适用于在不同 MySQL/MariaDB 版本之间进行迁移,或者当您需要对权限进行更精细的控制时。它通过提取实际定义用户权限的 GRANT 语句来实现迁移。

生成 GRANT 命令:

mysql -B -N -u root -p -e "SELECT CONCAT('SHOW GRANTS FOR ''', user, '''@''', host, ''';') FROM mysql.user WHERE user NOT IN ('mysql.infoschema', 'mysql.session', 'mysql.sys', 'root')" \

| mysql -B -N -u root -p \

| sed 's/$/;/' > all_user_grants.sql

这个复杂的命令会查询 mysql.user 表,为所有非系统用户生成 SHOW GRANTS 语句,然后执行这些 SHOW GRANTS 语句,并将它们的输出(即实际的 GRANT 命令)追加到 all_user_grants.sql 文件中。

审查和导入 GRANT 脚本:

打开 all_user_grants.sql 文件进行审查。您可以根据需要删除不希望迁移的用户账户或特定的权限行。然后,在新服务器上运行该脚本:

mysql -u root -p < all_user_grants.sql

虽然并非严格必要,但在导入完成后运行 FLUSH PRIVILEGES; 仍然是一个良好的习惯,可以确保所有权限立即生效。

大型 SQL 文件的处理与导入优化

处理大型数据库时,导入过程可能会变得非常缓慢或占用大量系统资源。以下是一些管理和加速大型数据库转储文件导入的策略:

1. 使用压缩以节省空间和时间

通过管道将 mysqldump 的输出直接导入 gzip 以创建压缩文件。在导入时,则使用 gunzip 进行解压缩并直接导入到数据库。

导出(压缩):

mysqldump -u username -p database_name | gzip > database_name.sql.gz

导入(解压缩):

gunzip < database_name.sql.gz | mysql -u username -p database_name

2. 暂时禁用外键检查与唯一约束

在导入大量数据时,禁用外键检查 (foreign_key_checks) 和唯一性检查 (unique_checks) 可以显著提高导入速度,因为数据库不需要在每次插入时都进行这些复杂的验证。同时,禁用自动提交 (autocommit),将所有操作作为一个大的事务来处理,也能减少磁盘写入和日志开销。

在 .sql 文件的开头添加以下语句(或在导入前手动执行):

SET foreign_key_checks = 0;

SET unique_checks = 0;

SET autocommit = 0;

导入结束后,务必重新启用它们并提交更改:

SET foreign_key_checks = 1;

SET unique_checks = 1;

COMMIT;

3. 使用 --quick 和 --single-transaction 标志

导出大型 InnoDB 数据库时,这两个 mysqldump 选项至关重要:

--single-transaction:创建一个事务隔离级别为 REPEATABLE READ 的快照。这意味着在导出过程中,即使有其他客户端正在修改数据,导出的数据也是一致的,且不会阻塞其他读写操作。这对于生产环境中的在线备份尤其重要。

--quick:强制 mysqldump 一行一行地从服务器检索数据,而不是一次性将所有数据加载到内存中。这可以大大减少内存使用,防止因为内存不足而导致导出失败。

mysqldump -u username -p --single-transaction --quick database_name > database_name.sql

4. 将 SQL 文件拆分成更小的块

对于超大型转储文件,一次性导入可能会导致超时或内存溢出。使用 split 命令将其分割成更小的、可管理的片段(例如,每 5000 行一个文件):

split -l 5000 large_dump.sql chunk_

这会生成 chunk_aa, chunk_ab, chunk_ac 等文件。然后,您可以按顺序导入这些块:

for file in chunk_*; do

mysql -u username -p database_name < "$file"

done

5. 批量数据导入:LOAD DATA INFILE

如果您的数据是 .csv 或 .tsv 等纯文本格式,并且您需要将它们导入到现有的表中,LOAD DATA INFILE 命令通常比通过 SQL INSERT 语句导入快得多。

LOAD DATA INFILE '/path/to/file.csv'

INTO TABLE table_name

FIELDS TERMINATED BY ',' -- 字段分隔符,例如逗号

LINES TERMINATED BY '\n' -- 行分隔符,例如换行符

IGNORE 1 LINES; -- 跳过文件中的第一行(通常是标题行)

注意:为了使用 LOAD DATA INFILE,MySQL/MariaDB 服务器上的 local_infile 配置需要启用,并且文件路径必须是服务器可访问的路径。

常见错误与避免策略

在导入和导出 MySQL 或 MariaDB 数据库时,一些常见的疏忽可能导致数据丢失或操作失败。了解这些问题并采取预防措施至关重要。

导入到错误的数据库

问题:未仔细检查目标数据库名称,导致数据被导入到非预期位置,甚至覆盖了现有数据。

避免:在执行导入命令前,务必仔细检查目标数据库名称。导入后,可以使用 USE your_database; SHOW TABLES; 和 SELECT COUNT(*) FROM your_table; 等命令确认数据是否正确导入。

忘记创建目标数据库

问题:mysql 导入命令假定目标数据库已存在。如果数据库不存在,导入会失败。

避免:在导入之前,始终先使用 CREATE DATABASE database_name; 命令创建目标数据库。或者,在导出时使用 mysqldump 的 --databases 选项,这会在转储文件中包含 CREATE DATABASE 和 USE 语句。

使用不正确的凭据或权限不足

问题:用于导出或导入的数据库用户没有足够的权限(例如 SELECT、LOCK TABLES、INSERT、CREATE 等)。

避免:确保用户拥有执行所需操作的所有权限。如果不确定,可以使用 root 用户进行操作(仅限安全环境或测试环境)。在生产环境中,应使用具有最小必要权限的用户。

导出时未使用 --add-drop-table

问题:如果导入的数据库中已经存在同名表,并且转储文件不包含删除表的语句,导入会因“表已存在”(“Table already exists”)错误而失败。

避免:在 mysqldump 命令中添加 --add-drop-table 标志。这会使得转储文件在每个 CREATE TABLE 语句之前包含 DROP TABLE IF EXISTS 语句,确保表在重新创建前被安全删除。

跳过用户权限迁移

问题:标准的数据库转储(mysqldump database_name)不包含用户账户和权限信息。如果在迁移后不单独处理,新服务器上的应用程序可能无法连接数据库。

避免:务必按照本教程“用户权限的导出与迁移”部分的方法,单独导出和导入用户账户和权限信息,并在导入后运行 FLUSH PRIVILEGES;。

未验证字符集和排序规则兼容性

问题:源数据库和目标数据库的字符集或排序规则(collation)不匹配,可能导致导入后文本乱码或数据比较行为异常。

避免:在导出和导入时,考虑使用 --default-character-set 选项来指定字符集。在迁移前,检查并确保源和目标服务器的 character_set_server 和 collation_server 设置一致。

未优化大型文件导入

问题:直接导入一个巨大的 .sql 文件可能耗时过长,甚至因内存或连接超时而失败。

避免:采用本教程“大型 SQL 文件的处理与导入优化”部分介绍的策略,如使用压缩、禁用外键检查和自动提交、拆分文件或考虑 LOAD DATA INFILE。

忽略文件权限或文件路径

问题:指定的 .sql 文件不存在于正确的路径,或者当前用户没有读取该文件的权限。

避免:在执行导入命令前,使用 ls -l /path/to/your/file.sql 确认文件路径的正确性及文件权限。

通过避免这些常见错误,可以节省大量时间,防止潜在的数据丢失,并确保 MySQL 或 MariaDB 数据库操作的流程更加顺畅。在执行任何关键的导入或迁移任务之前,强烈建议在非生产环境中进行充分的测试。

常见问题解答 (FAQs)

1. mysqldump 与二进制备份有何区别?

mysqldump (逻辑备份):生成包含 SQL 语句的文本文件。它独立于数据库服务器的版本和操作系统,因此具有很强的可移植性,适用于跨版本或跨平台迁移。缺点是恢复速度相对较慢,对于非常大的数据库可能效率不高。

二进制备份 (物理备份):直接复制磁盘上的实际数据文件(如 InnoDB 的 .ibd 文件、.frm 文件等)。它速度快,是恢复整个服务器或大型数据库的理想选择。但缺点是与服务器的文件结构和版本紧密绑定,通常只能恢复到相同或兼容版本的服务器上。

2. 能否将 MySQL 转储导入 MariaDB?

通常情况下是可以的。MySQL 和 MariaDB 在语法和功能上保持了高度兼容性,尤其是在其主要版本范围内。然而,如果转储文件包含特定于某个新 MySQL 版本独有的功能或语法(例如某些较新的 JSON 函数或特定的 SQL 语句),则在导入 MariaDB 时可能需要进行少量调整。

3. 如何只导出数据库的架构(不含数据)?

使用 mysqldump 的 --no-data 标志:

mysqldump -u username -p --no-data database_name > schema_only.sql

这会创建一个只包含 CREATE TABLE、CREATE VIEW、CREATE PROCEDURE 等语句的转储文件,不包含 INSERT 数据行。

4. 导入时出现“table already exists”错误怎么办?

此错误表示目标数据库中已经存在与转储文件中同名的表。解决方法有:

在导出时添加 --add-drop-table 标志:这将使转储文件在每个 CREATE TABLE 语句之前包含 DROP TABLE IF EXISTS 语句,确保在重新创建表之前先删除它们。

在导入前创建新的空数据库:这是最简单、最安全的做法,确保目标数据库是干净的。

手动编辑转储文件:如果只需要导入部分表,可以打开 data-dump.sql 文件,删除冲突表的 CREATE TABLE 和 INSERT 语句。

5. 能否一次性导出多个数据库?

可以。使用 mysqldump 的 --databases 选项,后跟用空格分隔的数据库名称列表:

mysqldump -u username -p --databases db1 db2 db3 > multi-database-dump.sql

这将为每个数据库生成 CREATE DATABASE 和 USE 语句,并将它们的数据一并导出。

6. 如何导出服务器上的所有数据库?

使用 mysqldump 的 --all-databases 选项:

mysqldump -u root -p --all-databases > all_databases.sql

这将创建包含所有用户数据库以及系统数据库(如 mysql, information_schema, performance_schema, sys)的完整备份。此选项通常用于完整服务器迁移或灾难恢复场景。

7. 将转储导入实时数据库安全吗?

应谨慎操作。如果转储文件包含 DROP TABLE、TRUNCATE TABLE 或 INSERT 语句,它可能会覆盖、删除或复制现有数据。在对生产环境进行任何导入操作之前,务必:

在测试环境中进行全面测试:确保导入过程和结果符合预期。

备份实时数据库:在导入前对生产数据库进行完整备份,以防万一。

审查转储文件:仔细检查转储文件中的 SQL 语句,特别是那些具有破坏性或可能影响现有数据的命令。

8. 为什么导入耗时过长?

导入过程缓慢可能有多种原因:

数据集过大:导入的数据量巨大。

外键检查已启用:每个插入或更新操作都需要验证外键约束。

频繁的索引更新:每次插入数据时,相关的索引都需要更新。

自动提交已启用:每个 INSERT 语句都作为一个单独的事务提交,增加了 I/O 开销。

服务器资源不足:CPU、内存或磁盘 I/O 成为瓶颈。

优化建议:

在导入前禁用外键检查 (SET foreign_key_checks = 0;) 和自动提交 (SET autocommit = 0;)。

确保 mysqldump 导出时使用了 --quick 和 --single-transaction 标志。

考虑使用压缩(gzip)来减少传输时间。

对于纯数据导入,使用 LOAD DATA INFILE 命令可能更快。

如果文件过大,可以拆分成小文件分批导入。

总结

本教程详细讲解了如何使用 mysqldump 和 mysql 工具在 MySQL 或 MariaDB 中执行数据库的导出和导入操作。我们从基础的完整数据库迁移讲起,逐步深入到选择性地处理特定表、迁移用户权限,并提供了针对大型 SQL 文件的高效处理策略。掌握这些技术对于日常的数据库备份、服务器迁移、开发环境复制以及故障恢复至关重要。通过熟练运用这些命令行工具和优化技巧,您将能够更可靠、高效地管理开发和生产系统中的数据库。

关于

关注我获取更多资讯

📢 公众号

💬 个人号

本文链接地址:https://blog.eimoon.com/p/mysql-mariadb-database-import-export/

作者:eimoon.com

分享转载说明:本文由作者原创,转载请注明出处。