SELECT INTO OUTFILE 是异构迁移导出 CSV 最高效方式,但需满足 FILE 权限、secure_file_priv 配置及路径限制;mysqldump 不适合因输出非纯 CSV、字段格式不可控、不支持自定义分隔符等。

直接导出 CSV 用于异构迁移,SELECT INTO OUTFILE 是最高效的选择——前提是目标 MySQL 实例允许且你有文件系统写入权限。其他方式(如 mysqldump 或客户端重定向)要么不生成纯 CSV,要么性能差、编码难控,容易在跨数据库导入时失败。
为什么不用 mysqldump 导出 CSV?
mysqldump 本质是逻辑备份工具,输出的是可执行的 SQL 语句,不是结构化文本。即使加 --tab 参数,它也只生成两份文件(.sql + .txt),其中 .txt 的字段分隔、引号包裹、换行符等行为不可靠,且默认不带表头、不处理 NULL 值为 \N,后续导入到 PostgreSQL / ClickHouse / Excel 等系统时极易出错。
- 它不支持自定义
fields terminated by和enclosed by的组合输出 - 导出大表时会锁表(除非加
--single-transaction,但该参数对 MyISAM 无效) - 无法在语句中嵌入列别名或计算字段,灵活性远低于原生
SELECT
SELECT INTO OUTFILE 的硬性前提和绕过方案
执行 SELECT INTO OUTFILE 要求同时满足三个条件:当前用户有 FILE 权限、MySQL 配置了 secure_file_priv、目标路径必须落在该配置指定的目录内。常见报错 ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option... 就源于此。
使用 qbo-mileage CLI 及用户凭证,从 Airtable、Outlook 或 Google Calendar 记录生成 QuickBooks Online 里程 CSV 文件。
- 查当前限制:
SHOW VARIABLES LIKE 'secure_file_priv';,返回值类似/var/lib/mysql-files/ - 不能写到
/tmp或用户家目录,哪怕你有 OS 写权限也不行 - 如果返回
NULL,说明该功能被彻底禁用,此时只能改用客户端导出(如mysql -e "SELECT ..." > out.csv),但要注意 shell 层面的编码和字段分隔问题 - 临时启用(仅限测试环境):修改
my.cnf,加一行secure_file_priv = "",然后重启 MySQL —— 生产环境严禁这么做
导出带表头的 CSV 并兼容 Excel 打开
MySQL 原生不支持自动加表头,但可以用 UNION ALL 拼接一行字符串常量。关键在于字段类型对齐和引号包裹,否则 Excel 会把数字当科学计数法、把带逗号的地址切碎。
SELECT 'id', 'name', 'email', 'created_at'
UNION ALL
SELECT
CAST(id AS CHAR),
CONCAT('"', REPLACE(REPLACE(name, '"', '""'), '\n', ' '), '"'),
CONCAT('"', REPLACE(REPLACE(email, '"', '""'), '\n', ' '), '"'),
created_at
FROM users
INTO OUTFILE '/var/lib/mysql-files/users_export.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
-
CAST(... AS CHAR)防止数字字段被导出为空或乱码 -
REPLACE(..., '"', '""')是 Excel 兼容的双引号转义方式(CSV RFC 4180) -
LINES TERMINATED BY '\n'在 Linux/macOS 下正常;若目标是 Windows Excel,需改成'\r\n' - 避免在
SELECT中使用*,显式列出字段并控制顺序和类型转换
超大表导出时防止内存溢出和锁表
单次导出千万级数据,SELECT INTO OUTFILE 仍可能因排序缓冲区(sort_buffer_size)或临时表撑爆内存。更稳妥的做法是分批次导出,用主键或时间字段切片:
SELECT id, name, email FROM users WHERE created_at BETWEEN '2025-01-01' AND '2025-06-30' INTO OUTFILE '/var/lib/mysql-files/users_2025_h1.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
- 确保
WHERE条件字段上有索引,否则全表扫描反而更慢 - 不要用
LIMIT+OFFSET分页,偏移越大越慢;改用“游标式”分片:WHERE id > 1000000 AND id - 导出前关闭 autocommit 并设低隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;,减少 MVCC 开销 - 如果表正在写入,优先选
--single-transaction(InnoDB)或FLUSH TABLES WITH READ LOCK(MyISAM),但后者会阻塞写入
真正容易被忽略的是字符集链路一致性:从 MySQL 连接层(character_set_client)、结果集(character_set_results)、到导出文件存储(必须 UTF-8 编码),再到目标系统(如 PostgreSQL 的 ENCODING 'UTF8')——任一环错位,中文就变问号或 Mojibake。别只盯着 SQL 语句,先 SHOW VARIABLES LIKE 'character\_set%'; 看清底色。

















