如何高效导出60GB级SQL单表数据至多个CSV文件?
高效导出大SQL表为多份CSV的方案
一、使用数据库原生工具(推荐,性能最优)
1. bcp命令行工具
这是SQL Server原生的批量导入导出工具,性能远高于C#逐行读取逻辑,适配超大数据量场景:
- 按行号拆分:借助
ROW_NUMBER()函数分批查询,循环执行bcp命令生成多份文件。示例:-- 导出第1批:前100万行 bcp "SELECT * FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY id) AS rn FROM YourTable) t WHERE rn BETWEEN 1 AND 1000000" queryout "D:\export\batch_1.csv" -S YourServer -d YourDB -U username -P password -c -t, -r\n -- 导出第2批:1000001到2000000行,以此类推 - 按业务字段拆分:如果表有日期、分区键等维度字段,直接过滤导出,比如按月份拆分:
bcp "SELECT * FROM YourTable WHERE create_time >= '2023-01-01' AND create_time < '2023-02-01'" queryout "D:\export\202301.csv" -S YourServer -d YourDB -U username -P password -c -t, -r\n
2. SQL Server Integration Services (SSIS)
适合可视化配置复杂拆分逻辑,无需手写大量代码:
- 新建SSIS包,添加数据流任务,用OLE DB源读取目标表。
- 添加条件拆分组件,按行号、业务字段等规则拆分数据流向。
- 每个拆分分支连接平面文件目标,指定不同CSV路径,运行包即可自动生成多份文件。
- 优势:自带错误处理、批量优化机制,稳定支撑60GB级数据导出。
二、优化C#代码实现
如果必须用C#处理,可通过批量读取+分文件写入优化,避免内存溢出:
1. 分页批量读取写入
用OFFSET ... FETCH NEXT实现分页,每次读取固定行数(比如10万行)写入单个CSV:
int batchSize = 100000; int currentPage = 1; while (true) { string sql = $"SELECT * FROM YourTable ORDER BY id OFFSET {(currentPage - 1) * batchSize} ROWS FETCH NEXT {batchSize} ROWS ONLY"; using (SqlCommand cmd = new SqlCommand(sql, connection)) { using (SqlDataReader reader = cmd.ExecuteReader()) { if (!reader.HasRows) break; string filePath = $"D:\\export\\batch_{currentPage}.csv"; using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8, 1024 * 1024)) // 1MB缓冲提升写入效率 { // 写入表头 for (int i = 0; i < reader.FieldCount; i++) { writer.Write($"\"{reader.GetName(i)}\""); if (i < reader.FieldCount - 1) writer.Write(","); } writer.WriteLine(); // 批量写入数据行 while (reader.Read()) { for (int i = 0; i < reader.FieldCount; i++) { object value = reader.IsDBNull(i) ? "" : reader.GetValue(i); writer.Write($"\"{value.ToString().Replace("\"", "\"\"")}\""); if (i < reader.FieldCount - 1) writer.Write(","); } writer.WriteLine(); } } } } currentPage++; }
2. 流式读取大字段
若表包含NVARCHAR(MAX)、VARBINARY(MAX)等大字段,添加CommandBehavior.SequentialAccess避免内存过载:
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { // 读取逻辑不变,大字段可通过reader.GetChars/GetBytes分段读取 }
三、关键注意事项
- 优先用数据库原生工具,性能比C#代码高3-10倍,稳定性更强。
- 拆分时优先使用有序主键或分区键做分页依据,避免全表扫描拖慢速度。
- 处理CSV特殊字符:引号、逗号、换行符需转义,避免文件格式损坏。
- 导出前可估算单文件大小(比如按1GB/文件),提前规划拆分批次数量。
内容的提问来源于stack exchange,提问作者Srini
相关产品推荐
相关产品推荐

