select ... into outfile 是 mysql 原生导出中最快的方案,因其绕过网络协议栈和客户端解析,由 server 线程直写本地磁盘,路径最短;但需 file 权限、secure_file_priv 允许路径、绝对路径且文件不能预存。

直接结论:在 MySQL 原生导出场景下,SELECT ... INTO OUTFILE 是目前单机导出速度最快的方案,显著快于 mysqldump、mysql 客户端重定向(mysql -e "SELECT..." > file)或应用层逐行 fetch。
为什么 SELECT INTO OUTFILE 速度最快?
它绕过了网络协议栈和客户端解析层,由 server 线程直接将结果写入服务器本地磁盘文件,全程不经过 MySQL 协议序列化/反序列化,也不走网络 socket。数据从存储引擎缓冲区 → server 格式化 → 文件 I/O,路径最短。
对比之下:
-
mysqldump会为每行生成完整 INSERT 语句,大量字符串拼接 + SQL 解析开销 -
mysql -e "SELECT..." > file仍需经 MySQL 协议打包、客户端解包、再转义输出(如 \t → tab,\n → 换行),还可能触发字符集转换 - 应用层(Python/Java)fetch 多数是逐行或小批量拉取,网络往返 + 内存拷贝 + 编码处理叠加延迟明显
SELECT INTO OUTFILE 的硬性限制与避坑点
速度快的前提是满足其运行约束,否则会报错或静默失败:
- 必须有
FILE权限(GRANT FILE ON *.* TO 'user'@'host'),且该权限不能被限制在某个 database 下 - 目标路径必须是 MySQL server 进程可写的**本地绝对路径**(如
/var/lib/mysql-files/export.csv),不能是相对路径或客户端路径 - 文件名不能已存在(MySQL 不覆盖),否则报错
ERROR 1086 (HY000): File 'xxx' already exists - 默认使用
secure_file_priv配置限定可写目录;执行SHOW VARIABLES LIKE 'secure_file_priv';查看允许路径,超出则报错ERROR 1290 (HY000) - 字段含换行符、引号、分隔符时,不会自动加引号或转义——需手动用
REPLACE()或CONCAT()处理,否则 CSV 解析会错位
实操建议:如何安全高效地导出百万级以上数据
以导出用户表为例,兼顾速度与可用性:
SELECT id, REPLACE(REPLACE(user_name, '\r', ''), '\n', ' ') AS user_name, email INTO OUTFILE '/var/lib/mysql-files/users_202406.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM users WHERE created_at >= '2024-01-01';
关键点说明:
- 用
FIELDS TERMINATED BY ','和OPTIONALLY ENCLOSED BY '"'兼容常见 CSV 工具读取 -
REPLACE()清除字段内换行符,避免破坏LINES TERMINATED BY逻辑 - 务必加
WHERE条件或LIMIT控制单次导出量,防止锁表或 OOM(尤其 MyISAM 表) - InnoDB 表建议开启
innodb_locks_unsafe_for_binlog=OFF(默认),避免长事务阻塞 - 导出后立刻用
ls -lh和head校验文件大小与格式,别等传到客户端才发现缺列
替代方案仅在特定条件下可行
如果无法使用 SELECT INTO OUTFILE(比如没 FILE 权限、云数据库禁用该功能),才考虑降级方案:
-
mysqldump --tab:底层也调用SELECT INTO OUTFILE,但要求有FILE权限 + 目录可写,且会额外导出建表语句(.sql 文件),适合整库迁移 -
mysqlpump(MySQL 5.7+):多线程 dump,但仍是 SQL 文本导出,速度仍远低于INTO OUTFILE - Percona Toolkit 的
pt-archiver:支持流式分批导出,适合边查边写文件或同步到其他系统,但单次吞吐不如原生命令
真正卡在导出性能瓶颈时,优先检查 secure_file_priv 和权限,而不是换工具——多数慢,是因为根本没走对路。











