数据导入导出看起来是数据库操作里最基础的一环,但真到实操时,很多人会发现坑比想象中多:导出的SQL文件恢复时报字符集错误、CSV文件里带换行的文本字段把整行数据切碎、几百兆的表用图形化工具导出直接卡死。MySQL和PostgreSQL作为使用最广泛的两款开源数据库,各自提供了一套成熟的导入导出工具,理解它们的差异和适用场景,是高效完成备份、迁移和数据交换的前提。

MySQL的数据导出与导入方法
MySQL官方提供的mysqldump是最经典的导出工具,它把数据库结构和数据转储成SQL语句文件。最基本的用法是指定用户名、密码和数据库名,导出的文件可以直接用mysql客户端执行恢复。默认情况下mysqldump会导出建表语句和INSERT语句,适合做逻辑备份。
mysqldump -u root -p --databases mydb > mydb_backup.sql # 只导出数据不导出结构 mysqldump -u root -p --no-create-info mydb mytable > data_only.sql # 恢复导入 mysql -u root -p mydb < mydb_backup.sql
几个参数值得特别注意:--single-transaction用于InnoDB表,能在不锁表的情况下拿到一致性快照,生产环境导出基本必加;--default-character-set=utf8mb4可以避免中文乱码;如果目标库表已存在,配合--add-drop-table能先删后建。导出大表时还可以加--extended-insert,把多行数据合并成一条INSERT语句,文件体积和执行速度都会明显改善。
对于CSV格式的数据交换,MySQL提供了LOAD DATA INFILE,这是导入海量文本数据最快的方式,比逐条执行INSERT快一个数量级以上。导出侧则可以用SELECT ... INTO OUTFILE,但要注意这个路径受secure_file_priv变量限制,如果导出报错提示权限问题,先检查该变量指定的目录。
-- 导入CSV,忽略首行表头 LOAD DATA INFILE '/var/lib/mysql-files/users.csv' INTO TABLE users FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS; -- 导出为CSV SELECT id, name, email FROM users INTO OUTFILE '/var/lib/mysql-files/users_out.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
如果文件由客户端上传,还可以用LOAD DATA LOCAL INFILE,但这需要在服务端和客户端同时开启local_infile开关,出于安全考虑部分云数据库默认关闭,需要根据实际情况权衡。
PostgreSQL的导入导出工具链
PostgreSQL的对应工具是pg_dump和pg_restore。pg_dump支持两种输出格式:纯SQL文本格式和自定义压缩格式。纯文本格式通用性最好,用psql直接执行即可;自定义格式(-Fc)则配合pg_restore使用,支持并行恢复和选择性恢复单个表,大数据量场景下明显更灵活。
# 导出为自定义压缩格式 pg_dump -U postgres -Fc mydb > mydb.backup # 并行恢复,4个线程同时执行 pg_restore -U postgres -j 4 -d mydb mydb.backup # 导出纯SQL格式 pg_dump -U postgres -s mydb > schema.sql # -s 表示只导出表结构
PostgreSQL在文本数据处理上比MySQL更彻底的一点是COPY命令。COPY是服务端命令,直接读写服务器本地文件;而\copy是psql的元命令,在客户端执行,读写的是客户端所在机器的文件,远程连接数据库时通常只能用后者。两者语法几乎一致,但作用范围不同,这是新手最容易混淆的地方。
-- 服务端COPY,导入CSV COPY users(id, name, email) FROM '/tmp/users.csv' WITH (FORMAT csv, HEADER true); -- 在psql中使用客户端版本 \copy users(id, name, email) FROM 'local_users.csv' WITH (FORMAT csv, HEADER true) -- 导出查询结果 \copy (SELECT * FROM users WHERE created_at > '2024-01-01') TO 'recent.csv' WITH (FORMAT csv, HEADER true)
COPY导入数据的速度同样远超INSERT语句,而且对CSV的解析遵循标准规范,带引号、带逗号、带换行的字段都能正确处理。如果数据源是JSON,PostgreSQL还支持直接COPY到JSONB字段,配合jsonb_to_record等函数可以做半结构化数据的入库。
两大数据库互导与迁移实战
MySQL迁移到PostgreSQL是常见需求。小数据量场景下,最直接的方案是双方都以CSV为中间格式:MySQL用SELECT INTO OUTFILE导出,PostgreSQL用COPY导入。但要注意几个兼容性问题:MySQL导出的转义字符默认是反斜杠风格,PostgreSQL的CSV解析遵循标准引号转义,所以导出时务必指定ENCLOSED BY '"'和ESCAPED BY '',让MySQL输出标准CSV。
-- MySQL侧导出标准CSV SELECT id, name, content FROM articles INTO OUTFILE '/tmp/articles.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '' LINES TERMINATED BY '\n'; -- PostgreSQL侧导入 COPY articles(id, name, content) FROM '/tmp/articles.csv' WITH (FORMAT csv);
字段类型映射是迁移中最容易踩坑的部分。MySQL的TINYINT(1)常被ORM映射成布尔值,迁到PostgreSQL需要转成boolean;DATETIME对应PostgreSQL的timestamp,但MySQL的零值日期0000-00-00在PostgreSQL中不合法,导入前必须清洗;自增主键MySQL用AUTO_INCREMENT,PostgreSQL用SERIAL或IDENTITY列,表结构需要改写。另外MySQL默认对INSERT隐式做类型宽松转换,PostgreSQL则严格得多,数字字符串混用会直接报错。
数据量较大或表结构复杂时,建议使用专门的迁移工具,例如pgloader,它能自动处理类型转换、字符集和增量加载,一条命令即可完成整库迁移:
LOAD DATABASE
FROM mysql://root:password@localhost/mydb
INTO postgresql://postgres:password@localhost/mydb
WITH include drop, create tables, create indexes, reset sequences;常见问题与性能优化建议
导入导出过程中的高频问题集中在三块。第一是字符集乱码,导出导入两侧的编码必须一致,MySQL侧通过--default-character-set指定,PostgreSQL侧通过PGCLIENTENCODING环境变量或client_encoding参数控制,涉及GBK老数据时要先确认源库真实编码。第二是换行符问题,Windows生成的CSV是CRLF换行,导入到Linux环境的数据库时LINES TERMINATED BY '\r\n'要写对,否则最后一列会多出不可见的回车符。第三是权限与路径,无论MySQL的secure_file_priv还是PostgreSQL的COPY,都要求文件路径在服务端可访问且数据库进程有读写权限。
性能方面,导出大数据量时建议按表拆分、按主键范围分批导出,避免单个超大文件;导入前临时关闭索引和约束(PostgreSQL可以先删索引导完再建,MySQL可以设置unique_checks=0),导完再恢复,整体耗时往往能缩短一半以上。导入过程中把事务打包提交,而不是依赖每条语句自动提交,也是重要的提速手段。最后别忘了验证环节:导完后核对行数、抽查关键字段、确认自增序列已同步(PostgreSQL迁移后序列值常需要手动setval),这些细节决定了迁移结果是否真正可用。
MySQL导出数据PostgreSQL导入mysqldump修改时间:2026-09-15 19:12:35