【问题标题】:Bulk data insertion in SQL Server table from delimited text file using c#使用 c# 从分隔文本文件中批量插入 SQL Server 表中的数据
【发布时间】:2012-08-04 03:31:10
【问题描述】:

我有制表符分隔的文本文件。文件大约 100MB。我想将此文件中的数据存储到 SQL Server 表中。该文件存储在 sql server 中时包含 100 万条记录。实现这一目标的最佳方法是什么?

我可以在 c# 中创建内存数据表,然后将其上传到 sql server,但在这种情况下,它会将整个 100 MB 文件加载到内存中。如果文件变大了怎么办?

【问题讨论】:

  • 为什么不只使用BULK INSERT 命令?
  • @pst 如果我没记错的话,这要求文件与 SQL Server 位于同一服务器上,这可能是发帖者的问题

标签: c# sql bulkinsert


【解决方案1】:

没问题; CsvReader 将处理大多数分隔文本格式,并实现IDataReader,因此可用于提供SqlBulkCopy。例如:

using (var file = new StreamReader(path))
using (var csv = new CsvReader(file, true)) // true = first row is headers
using (var bcp = new SqlBulkCopy(connectionString))
{
    bcp.DestinationTableName = "Foo";
    bcp.WriteToServer(csv);
}

请注意,CsvReader 有很多选项更微妙的文件处理(指定分隔符规则等)。 SqlBulkCopy 是高性能批量加载 API - 非常高效。这是一个流式读写器 API;它不会一次将所有数据加载到内存中。

【讨论】:

  • 我明白了。这是由某人开发的,并且在 MIT 开源许可下。我正在寻找的是使用 Microsoft 提供的 SDK、API 来实现相同目标的最佳方法。不需要额外的许可证。
  • @SamirLakhani MIT 许可证非常开放,并授予您免费使用代码的许可证,前提是您在分发的作品中包含他们的许可证:en.wikipedia.org/wiki/MIT_License
【解决方案2】:

您应该逐行读取文件,因此您不必将整行加载到内存中:

using (var file = System.IO.File.OpenText(filename))
{
    while (!file.EndOfStream)
    {
        string line = file.ReadLine();

        // TODO: Do your INSERT here
    }
}

* 更新 *

“这将向 sql server 发出 100 万条单独的插入命令。有什么办法可以批量实现”

您可以使用参数化查询,它仍会发出 1M 插入,但仍会相当快。

或者,您可以使用SqlBulkCopy,但如果您不想使用第 3 方库,这将相当困难。如果您更愿意使用 MS 许可证,您可以使用 LINQ Entity Data Reader(在 Ms-PL 许可证下分发),它提供了 AsDataReader 扩展方法:

void MyInsertMethod()
{
    using (var bulk = new SqlBulkCopy("MyConnectionString"))
    {
        bulk.DestinationTableName = "MyTableName";
        bulk.WriteToServer(GetRows().AsDataReader());
    }
}

class MyType
{
    public string A { get; set; }
    public string B { get; set; }
}

IEnumerable<MyType> GetRows()
{
    using (var file = System.IO.File.OpenText("MyTextFile"))
    {
        while (!file.EndOfStream)
        {
            var splitLine = file.ReadLine().Split(',');

            yield return new MyType() { A = splitLine[0], B = splitLine[1] };
        }
    }
}

如果您也不想使用 MS 许可代码,您可以自己实现 IDataReader,但这将是一个 PITA。请注意,上面的 CSV 处理 (Split(',')) 并不可靠,而且表中的列名必须与 MyType 上的属性名相同。 TBH,我建议你在这个问题上使用 Marc 的答案

【讨论】:

  • @pst 我有点假设发帖人从问题的措辞中知道如何做那部分
  • 这将向 sql server 发出 100 万条单独的插入命令。有什么办法可以批量生产
  • @Cocowalla 为什么没有第三方库 SqlBulkCopy 会难以实现?我正在执行以下方式,它看起来不错: SqlBulkCopy bulkCopy = new SqlBulkCopy(...) bulkCopy.BulkCopyTimeout = 0; bulkCopy.DestinationTableName = ""; bulkCopy.WriteToServer(dt);其中 dt 是我通过解析文件填充的 DataTable。使用 StreamReader。
  • 因为您说您担心内存使用情况。如果您使用的是DataTable,那么您正在将整个文件加载到内存中。如果您不想这样做,并且不想使用任何第三方库,那么您可能必须自己实现 IDataReader
猜你喜欢
  • 2013-08-14
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多