C#读取MySQL 2500万行数据报System.OutOfMemoryException异常求解决
问题根源
你当前的实现里两个核心问题导致OOM:
- 单批次拉取行数过大:单次拉800万行,DataTable/DataSet的内存开销远高于数据本身的存储大小,800万行实际占用内存很容易超过3GB,三批同时存内存直接打满
- 已拉取的数据集未释放:symbolltp、rtp、ftp三个DataSet对象全程被引用,GC无法回收,2500万全量加载后内存直接溢出
解决方案
按优先级从高到低执行:
优先优化业务逻辑,减少数据拉取量
如果你的场景是需要对数据做统计、过滤,优先把计算逻辑下沉到MySQL端执行,用SQL完成聚合、筛选,只把最终需要的结果集拉到应用层,从根源上避免全量拉取2500万行数据,这是成本最低的解决方案。降低单批次拉取行数,及时释放内存
把单次拉取的maxLimit调整到10万~50万区间,根据你每行的数据大小调整,控制单批内存占用在100MB以内。处理完一批数据后立刻调用Dispose()释放DataSet,不要同时保留所有批次的数据集在内存中:
// 示例循环拉取逻辑,处理完一批释放一批 int currentSno = 0; const int batchSize = 200000; // 单次20万行,可根据实际情况调整 while(true) { using var batchDs = mAE_Repo.maa_5min_eq_his(currentSno, batchSize); if(batchDs.Tables[0].Rows.Count == 0) break; // 处理当前批次数据逻辑 ProcessBatchData(batchDs); // 更新偏移量 currentSno = Convert.ToInt32(batchDs.Tables[0].Rows[^1]["SNO"]); }
- 替换DataSet为轻量读取方案
如果不需要用到DataSet的离线编辑等特性,直接用MySqlDataReader流式读取数据,不需要将整批数据加载到内存,内存占用可以降低90%以上,同时修改SQL为参数化写法,避免SQL注入风险:
// 修改后的查询方法,流式处理每行数据 public void ReadMaa5minEqHis(int startSno, int batchSize, Action<MySqlDataReader> rowProcessor) { using var conn = new MySqlConnection("你的数据库连接字符串"); conn.Open(); using var cmd = new MySqlCommand("SELECT * FROM maa_5min_eq_his WHERE SNO>@sno LIMIT @limit", conn); cmd.Parameters.AddWithValue("@sno", startSno); cmd.Parameters.AddWithValue("@limit", batchSize); using var reader = cmd.ExecuteReader(); while(reader.Read()) { rowProcessor(reader); } }
- 运行环境校验
- 确认你的项目是64位运行:在项目属性→生成选项卡中,取消勾选「首选32位」,32位程序最大仅能使用4GB内存,开启gcAllowVeryLargeObjects也不会生效
- 如果确实需要全量加载所有数据到内存,将DataTable替换为
List<自定义实体类>,自定义实体类的内存开销远低于DataRow,2500万行数据可以节省至少50%的内存占用
- 修复资源泄漏问题
你当前的数据库连接仅在抛出异常时才会关闭,正常执行完连接会一直处于打开状态,统一用using块包裹MySqlConnection、MySqlCommand、MySqlDataReader等实现了IDisposable的对象,程序会自动释放资源不需要手动关连接。
内容的提问来源于stack exchange,提问作者ashok
相关产品推荐
相关产品推荐

