我发现将大型 CSV 文件导入 SQL Server 的最佳方法是使用 SqlBulkCopy 和 IDataReader 实现。这样做的好处是您没有将整个文件读入内存(使用 DataTable 方法就是这种情况),您可以控制发送到 SQL Server 的批处理的大小。不好的是你必须实现IDataReader,这是我见过的最长的MS接口之一。
我编写了一个 nuget 包,可以为您解决问题。它使用了很棒的CsvHelper 包,因此需要的配置很少。最简单的场景如下所示:
//Instantiate the reader, providing the list of columns which matches 1 to 1 the data table structure.
var dataReader = new CsvDataReader(filePath,
new List<TypeCode>(5)
{
TypeCode.String,
TypeCode.Decimal,
TypeCode.String,
TypeCode.Boolean,
TypeCode.DateTime
});
bulkCopyUtility.BulkCopy("TableName", dataReader);
还有针对更复杂场景的其他配置选项(灵活的列映射、csv 文件中不存在的其他静态列值、值转换)。
如果您有兴趣,该项目位于Github,并以nuget package 的形式提供。
作为参考,下面是如何使用SqlBulkCopy 和IDataReader:
public void BulkCopy(string tableName, IDataReader dataReader, Action<SqlBulkCopy> configureSqlBulkCopy)
{
using (SqlConnection dbConnection = new SqlConnection(connectionString))
{
dbConnection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(dbConnection))
{
bulkCopy.BatchSize = 3000; //Data will be sent to SQL Server in batches of this size
bulkCopy.EnableStreaming = true;
bulkCopy.DestinationTableName = tableName;
//This will ensure mapping based on names rather than column position
foreach (DataColumn column in dataReader.GetSchemaTable().Columns)
{
bulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
//If additional, custom configuration is required, invoke the action
configureSqlBulkCopy?.Invoke(bulkCopy);
try
{
// Write from the source to the destination.
bulkCopy.WriteToServer(dataReader);
}
finally
{
dataReader.Close();
}
}
}
}