我有一个CSV文件,我必须把它插入到一个SQL Server数据库。 有没有一种方法,以加快LINQ插入?
我创建了一个简单的方法储存库保存记录:
public void SaveOffer(Offer offer)
{
Offer dbOffer = this.db.Offers.SingleOrDefault (
o => o.offer_id == offer.offer_id);
// add new offer
if (dbOffer == null)
{
this.db.Offers.InsertOnSubmit(offer);
}
//update existing offer
else
{
dbOffer = offer;
}
this.db.SubmitChanges();
}
但是使用该方法,所述程序是然后使用ADO.net SQL插入物(新的SqlConnection,用于选择新的SqlCommand如果存在,为更新/插入新的SqlCommand)将所述数据的方式要慢得多。
在100K的CSV行大约需要一个小时VS 1分钟左右的ADO.net方式。 对于2M的CSV行花了ADO.net约20分钟。 LINQ增加了大约25分钟的2M行的30K。 我的数据库有3个表,在dbml的联系,但其他两个表是空的。 这些测试是与所有空表进行。
PS我试着使用SqlBulkCopy的,但我需要将其插入到数据库之前做提供一些转变,我认为失败SqlBulkCopy的目的。
更新/编辑:18小时后,LINQ版本仅增加了〜200K行。
我测试过的进口只是LINQ插入过了,也实在是太慢了与ADO.net比较。 我还没有看到刚刚插入/的SubmitChanges和选择/更新/插入/的SubmitChanges之间有很大的区别。
我还是要尽量批提交,手动连接到数据库,并编译查询。
Answer 1:
的SubmitChanges不批的变化,它的每个对象单个插入语句。 如果你想要做快速插入,我想你需要停止使用LINQ。
虽然是的SubmitChanges执行,启动SQL事件探查器和手表正在执行的SQL。
参见问题“能否LINQ to SQL的执行批量更新和删除?或者它总是做一个行更新一次?” 在这里: http://www.hookedonlinq.com/LINQToSQLFAQ.ashx
它链接到这篇文章: http://www.aneyfamily.com/terryandann/post/2008/04/Batch-Updates-and-Deletes-with-LINQ-to-SQL.aspx使用扩展方法来解决LINQ的无能批量插入和更新等。
Answer 2:
您是否尝试过包裹插入一个事务中和/或延迟db.SubmitChanges,让你可以批量插入几个?
交易帮助吞吐量通过减少需要用于FSYNC()的,并且延迟db.SubmitChanges会降低.NET的数量< - >分贝往返。
编辑:见http://www.sidarok.com/web/blog/content/2008/05/02/10-tips-to-improve-your-linq-to-sql-application-performance.html一些更优化原则。
Answer 3:
看看下面的页面,如何改变你的代码使用批量插入而不是使用LINQ的InsertOnSubmit()函数的简单步行通过。
你只需要在(提供)BulkInsert类添加到您的代码,做一些细微的改动你的代码,你会看到在性能上巨大的进步。
米凯什知识库- BulkInserts与LINQ
祝好运 !
Answer 4:
我想知道,如果你从过大的数据集的数据上下文积累的痛苦,使之缓慢,以解决针对内部身份缓存行(这是在一次检查SingleOrDefault
,而对于“未命中”我期望看到第二次打击,当实体化)。
我不记得100%短路无论是作品SingleOrDefault
(尽管它会在.NET 4.0中 )。
我会尝试抛弃数据上下文(提交-变化以及其替换为空)每n操作对于一些N -也许250或东西。
既然你调用SubmitChanges
目前每isntance,你也可能会浪费大量的时间检查三角洲-毫无意义的,如果你只改变了一行。 只有调用SubmitChanges
分批进行; 不是每个记录。
Answer 5:
亚历克斯给了最好的答案,但我认为一些东西被漏掉了。
一,你在这里的主要瓶颈被单独调用的SubmitChanges为每个项目。 一个问题,我不认为大多数人都知道的是,如果你没有自己手动开启您的DataContext的连接,然后在DataContext将反复打开和关闭它本身。 但是,如果你自己打开它,然后自己关闭它,当你完成绝,事情会更快,因为它不会每次都重新连接到数据库运行了很多。 试图找出为什么DataContext.ExecuteCommand()一次执行多个命令时是如此令人难以置信的慢时,我发现了这一点。
其他一些地区在那里你可以加快速度:
虽然LINQ to SQL的不支持你的直线上升批处理,您应该等待调用的SubmitChanges(),直到你首先分析了一切。 你不需要每次InsertOnSubmit调用后调用的SubmitChanges()。
如果实时数据的完整性是不是超级重要的,你可以在开始检查,看看如果供应已经存在之前检索offer_id列表从服务器返回。 这可能显著减少的时候,我们在调用服务器以获取现有项目时,它甚至不是那里的量。
Answer 6:
为什么不通过要约[]进入该方法,并将其提交到数据库之前在做缓存中的所有变化。 或者你可以使用组提交,这样你就不会跑出来的缓存。 最主要的是多长时间,直到你发送过来的数据,最大的浪费时间是在关闭和连接的开放。
Answer 7:
这个转换为编译的查询是我能想到的在这里提高你的表现的最简单的方法:
更改以下:
Offer dbOffer = this.db.Offers.SingleOrDefault (
o => o.offer_id == offer.offer_id);
至:
Offer dbOffer = RetrieveOffer(offer.offer_id);
private static readonly Func<DataContext, int> RetrieveOffer
{
CompiledQuery.Compile((DataContext context, int offerId) => context.Offers.SingleOrDefault(o => o.offer_id == offerid))
}
这种变化本身不会让它以最快的速度你ado.net版本,但是这将是一个显著的改善,因为编译时查询你每次运行这个方法时,动态构建表达式树。
正如一位海报已经提到,必须重构你的代码,所以如果你想获得最佳性能即提交更改只调用一次。
Answer 8:
你真的需要检查记录将其插入到数据库之前存在。 我认为是数据来自一个CSV文件看起来奇怪。
PS我试着使用SqlBulkCopy的,但我需要将其插入到数据库之前做提供一些转变,我认为失败SqlBulkCopy的目的。
我不认为它击败目的可言,为什么会呢? 只需填写与从CSV所有数据的简单数据集,并做了SqlBulkCopy的。 我做了类似的事情用30000+行的收集和进口时间从几分钟就到秒
Answer 9:
我怀疑这是不是插入或更新都需要很长的时间,而确定,如果你的报价已经存在的代码操作:
Offer dbOffer = this.db.Offers.SingleOrDefault (
o => o.offer_id == offer.offer_id);
如果你看一下优化这个,我想你会在正确的轨道上。 也许使用秒表类做了一些时间,这将有助于证明我是对还是错。
通常情况下,不使用LINQ到SQL时,你将有一个插入/更新程序或SQL脚本,将决定你通过记录是否已经存在。 你在做的LINQ,这当然绝不会希望以符合本地SQL的速度(这是当你使用SqlCommand并选择是否记录存在发生了什么),这种昂贵的操作在主键上寻找行动。
Answer 10:
那么你必须了解LINQ动态为你做,而不是手写的所有ADO操作产生的代码,所以它总是会占用更多的时间,那么你的手工代码。 它只是一个简单的方法来编写代码,但如果你想谈论性能,ADO.NET代码将取决于你如何写它总是会更快。
我不知道是否会LINQ尝试重用其最后陈述与否,如果是的话那么插入分隔条件与一批批更新可以提高性能点点。
Answer 11:
此代码运行正常,并防止大量的数据:
if (repository2.GeoItems.GetChangeSet().Inserts.Count > 1000)
{
repository2.GeoItems.SubmitChanges();
}
然后,在块体插入结束,使用:
repository2.GeoItems.SubmitChanges();
文章来源: Speed up LINQ inserts