4

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

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

4

2 回答 2

5

没问题; 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;它不会一次将所有数据加载到内存中。

于 2012-08-07T06:40:23.550 回答
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,但如果您不想使用 3rd 方库,这将相当困难。如果您更愿意使用 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。请注意,上面 ( Split(',')) 的 CSV 处理根本不可靠,并且表中的列名必须与 上的属性名称相同MyType。TBH,我建议您使用 Marc 对此的回答

于 2012-08-07T06:40:39.827 回答