使用LINQ2SQL插入大量记录
Posted
技术标签:
【中文标题】使用LINQ2SQL插入大量记录【英文标题】:Using LINQ2SQL to insert a large number of records 【发布时间】:2010-11-01 18:31:26 【问题描述】:我们有一个小型 c# 工具,我们将其用于解析数据文件、构建一些对象并将它们插入数据库。
逻辑本质上是。
string [] lines = File.ReadAllLines("C:\\Temp\\Data.dat")
foreach(string line in lines)
MyDataObject obj = ParseObject(line);
myDataContext.MyDataObjects.InsertOnSubmit(obj);
myDataContext.SubmitChanges();
一开始这很好,因为数据文件每天只有约 1000 行长 但最近这个文件已经增长到大约 30,000 行,而且这个过程变得非常缓慢。
SubmitChanges()
调用的一切都很好,但是一旦它开始转储过程
30,000 次插入数据库,它只是停止。作为测试,我模拟了 30,000 个插入语句并直接从 QA 运行它们。大约花了 8 分钟。
8 分钟后,C#/Linq 版本只完成了大约 25% 的插入。
有人对我如何优化这个有任何建议吗?
【问题讨论】:
【参考方案1】:如果您正在编写大量同质数据,SqlBulkCopy
可能是更合适的工具,例如可能与CsvReader
一起读取行(因为SqlBulkCopy
可以接受IDataReader
,这意味着您不'不必将所有 30k 行缓冲到内存中)。
如果数据是 CSV,这可以很简单:
using (CsvReader reader = new CsvReader(path))
using (SqlBulkCopy bcp = new SqlBulkCopy(CONNECTION_STRING))
bcp.DestinationTableName = "SomeTable";
bcp.WriteToServer(reader);
如果数据更复杂(不是 CSV),那么SimpleDataReader
可能有用 - 您只需对其进行子类化并添加代码来表示每行数据。
【讨论】:
Cheers Marc,沿着这条路走下去,在内存中建立了一个 DataTable 并将其传递给 BulkCopy 对象。不幸的是,它不是平面 CSV,在将其推送到服务器之前需要进行大量操作。谢谢【参考方案2】:前段时间我也有同样的问题。我在数据库中插入 1000000 个新条目,我发现每 500 个调用 SubmitChanges 是最快的方法。
我不能保证当时的 500 行是有史以来最快的,我们的环境很奇怪......
【讨论】:
我怀疑这与单个 SQL 命令可以包含的最大参数数有关。我相信最大值是 2100 个参数。如果您要插入 4 列的记录,则大约 500 列的最佳值是有意义的。【参考方案3】:您可能想尝试多线程方法。
-
将记录集划分为较小的大小(每个 1000 条?),将它们放入堆栈中
拥有一个类,该类将从堆栈顶部获取记录集并使用多线程类开始插入它,该类会打开 DataContext 并自行插入。
在插入时,会为下一组记录打开第二个类
内部逻辑决定一次可以运行多少个插入(5 个?10 个?)
这可能允许插入比仅仅每隔几条记录运行一次 SubmitChanges() 更快,因为多个插入可以同时发生。
【讨论】:
【参考方案4】:这是一项数据库任务,应通过 SSIS 并使用批量插入来完成。
我可以在几秒或几毫秒内插入 30,000 条记录(取决于列数和数据映射的复杂程度)。我有超过一百万条记录的导入,这些记录插入的时间比您一次循环遍历记录所花费的时间要少。我什至有一个 2000 万条记录文件只需要 16 分钟。
【讨论】:
是的,这很棒。然而这是不可行的。对于初学者来说,它在 SQL 2000 上,所以没有 ssis,这是 DTS 领域。其次,数据是从附属公司提交给我们的业务部门的。而且我很乐意为他们提供一个需要 2 分钟即可运行以上传数据的工具,而不是让他们完全访问数据库,以便他们可以与企业经理混在一起。 你可以用 DTS 做到这一点。然后让您的应用调用 DTS 包。或者使用批量插入在存储过程中执行此操作,并让您的应用调用该过程。【参考方案5】:老问题,但在寻找我自己的解决方案后,我遇到了this code project article,这非常好。基本上使用 Linq2Sql 属性来构建一个 DataTable,然后使用 SQLBulkCopy 插入,这比基本的 Linq2Sql 实现快得多。文章中的代码可能需要进行一些清理,并且可能会在使用外键的更复杂的场景中失败(我的模型中没有外键,尽管数据库中有)但非常适合我的需求。
【讨论】:
以上是关于使用LINQ2SQL插入大量记录的主要内容,如果未能解决你的问题,请参考以下文章