SELECT INTO OUTFILE是MySQL原生最高效导出方式,适用于百万级表部分字段导出,但需满足FILE权限、secure_file_priv路径限制及会话字符集正确设置,否则易因权限、路径或超时失败。

用 SELECT ... INTO OUTFILE 直接写文件最快
对百万级表只导出部分字段,SELECT ... INTO OUTFILE 是 MySQL 原生最高效的方式——它绕过客户端网络传输和字符集转换,由服务端直接写磁盘。前提是 MySQL 有写入目标路径的权限(secure_file_priv 限制),且你有 FILE 权限。
常见错误现象:ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement,说明 MySQL 被限制了导出路径。
- 先查允许路径:
SHOW VARIABLES LIKE 'secure_file_priv';,结果可能是/var/lib/mysql-files/或NULL(后者表示禁用) - 导出语句示例(注意字段名、分隔符、行终止符):
SELECT id, name, created_at FROM users WHERE status = 1 INTO OUTFILE '/var/lib/mysql-files/users_active.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY ' ';
- 字段顺序、类型、NULL 处理需提前确认:
NULL值默认导出为空字符串,若需显示N,加NULL子句(如FIELDS TERMINATED BY ',' NULL AS '\N')
mysqldump 只导数据不导建表语句 + 字段过滤
如果无法用 INTO OUTFILE(比如没 FILE 权限,或目标路径不可写),mysqldump 是次优选择,但必须关掉建表语句、关掉自动提交、指定字段,否则默认导全量结构+数据,慢且冗余。
容易踩的坑:不加 --no-create-info 会多出 CREATE TABLE 和 INSERT 混合内容;不指定 --fields-terminated-by 默认是 tab 分隔,不易被 Excel 或 CSV 工具识别。
- 基本命令(导出指定字段,CSV 格式):
mysqldump -u root -p --no-create-info --skip-extended-insert --fields-terminated-by=',' --lines-terminated-by=' ' --tab='/tmp/' testdb users --where="status=1" --columns=id,name,created_at
-
--tab参数会生成两个文件:users.txt(数据)和users.sql(建表语句,可忽略);--columns在 5.7+ 支持,低版本需用SELECT+mysqldump组合 - 性能影响:加
--skip-extended-insert会让每行一个INSERT,但对纯 CSV 导出无意义,反而拖慢;这里真正有用的是--single-transaction(InnoDB 表避免锁表)
导出时字段类型导致乱码或截断
导出含中文、emoji 或长文本字段时,INTO OUTFILE 和 mysqldump 都依赖连接层字符集。如果客户端连接用 latin1,而字段是 utf8mb4,导出后会出现乱码或截断(尤其 emoji 被转成 ?)。
关键点不在导出命令本身,而在发起导出的会话字符集设置。
- 执行导出前,显式设置连接字符集:
SET NAMES utf8mb4;
或在命令中指定:mysql -u user -p --default-character-set=utf8mb4 - 检查字段实际编码:
SHOW CREATE TABLE users;看name字段是否为utf8mb4;若为utf8(MySQL 的旧版伪 utf8),存 emoji 会失败,导出必然异常 - CSV 中引号包裹字段能防止逗号干扰,但若字段内容含换行符(
),INTO OUTFILE默认不转义,Excel 打开会错行;此时建议用REPLACE()清洗:REPLACE(REPLACE(name, ' ', ' '), ' ', ' ')
大表导出卡住或超时?调这些参数
百万行不是瓶颈,但默认的 net_write_timeout(60 秒)、max_allowed_packet(4MB)可能在导出长文本字段时触发中断或截断。
不要改全局配置,只需在当前会话或命令中临时调高:
- 对
INTO OUTFILE查询,执行前设:SET SESSION net_write_timeout = 300; SET SESSION max_allowed_packet = 512 * 1024 * 1024;
- 对
mysqldump,加参数:--net-read-timeout=300 --net-write-timeout=300 --max-allowed-packet=512M - 如果表有大 JSON 或 TEXT 字段,
max_allowed_packet必须大于单行最大可能长度,否则导出中途报错:Packets larger than max_allowed_packet are not allowed
导出路径权限、字符集会话设置、单行长度上限——这三个点不提前验证,哪怕语句写得再对,也会在最后一分钟失败。


















