根本原因是mysqldump默认启用mysql_store_result模式,将整表结果一次性加载至内存,1000万行×2kb/行≈20gb,远超客户端内存容量;必须加--quick启用mysql_use_result流式读取,边查边写,内存恒定几mb,并配合--single-transaction避免锁表。

mysqldump导出大表时为什么客户端会OOM
根本不是MySQL服务端崩了,是mysqldump进程自己把整张表结果全读进内存才挂的。默认启用mysql_store_result模式:查完所有行,再拼SQL写文件。1000万行 × 平均2KB/行 ≈ 20GB原始数据,还不算字符串对象头、Python字典开销、临时缓冲区——mysqldump进程直接被Linux OOM Killer干掉。
必须加--quick:强制切换为mysql_use_result流式读取,边查边写,内存恒定在几MB;顺手加--single-transaction(InnoDB)避免锁表;禁用--lock-tables——它既锁表又缓存全部数据,双重加压。
-
--skip-extended-insert仅用于调试,正式导出要关掉,否则单条INSERT可能超max_allowed_packet -
--extended-insert必须开:生成多值INSERT,减少SQL解析次数,提速最直接 -
--skip-triggers和--skip-routines若目标库不需要,就跳过,减小文件体积和导出时间
Java应用执行SELECT大结果集时JVM堆爆了怎么办
JDBC默认行为是把整个ResultSet加载进JVM堆,不等你调rs.next()就已分配完内存。这不是驱动bug,是设计如此——它假设你马上要遍历全部结果。
正确做法是显式启用流式查询:
- 用
PreparedStatement创建时指定游标类型:conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY) - 再调
setFetchSize(Integer.MIN_VALUE)(即-2147483648),通知MySQL驱动启用流式 - 或强转为MySQL特有接口:
((com.mysql.cj.jdbc.StatementImpl) stmt).enableStreamingResults()
注意:流式模式下不能调rs.last()、rs.getRow()或rs.getMetaData()(某些旧驱动版本会触发缓冲回填),也不能复用同一Statement执行其他查询——必须及时close(),否则连接泄露。
MyBatis里怎么安全做百万级导出
别用selectList(),那等于把全部记录塞进ArrayList。MyBatis支持两种流式路径,本质都是绕过ORM自动封装成List的逻辑:
- 用
Cursor<t></t>:Mapper方法返回Cursor<user></user>,配合fetchSize="-2147483648",然后在业务层用for (User u : cursor)逐条处理并刷CSV - 用
ResultHandler:自定义处理器,在handleResult()里直接写响应流,每处理一条就flush一次,内存只留单条对象
关键点:两种方式都要求数据库连接保持打开状态直到处理完毕,所以务必在try-with-resources或finally块中显式cursor.close()或确保ResultHandler生命周期可控——否则连接池耗尽比OOM来得还快。
导入大SQL文件时mysql命令行自己先OOM了
mysql -e "source huge.sql"或mysql 会把整个文件读进内存再解析。遇到含10万行VALUES的单条INSERT,客户端进程瞬间吃光几百MB,和max_allowed_packet无关。
解决方案分两步走:
- 拆文件:用
sed -n '/^INSERT INTO/p' dump.sql | split -l 8000 -a 3 - batch_提取并切分INSERT语句(前提是原dump用了--skip-extended-insert,保证每行一个INSERT) - 包事务:给每个分片加
START TRANSACTION;和COMMIT;,避免每条INSERT单独提交加重日志压力 - 控制客户端参数:用
mysql --net-buffer-length=1M --max-allowed-packet=64M压制解析阶段内存堆积(仅mysql 8.0+有效)
真正容易被忽略的是:服务端innodb_buffer_pool_size再大,也救不了客户端缓存行为;OOM的锅永远在客户端驱动层是否流式,而不是“数据太大”。











