如何加速DbSet.Add()?

时间:2010-12-04 19:48:22

标签: c# performance entity-framework sql-server-2008

我必须从CSV文件导入大约30k行到我的SQL数据库,这可能需要20分钟。

使用分析器进行故障排除向我显示 DbSet.Add占用的时间最多,但为什么?

我有这些Entity Framework Code-First类:

public class Article
{
    // About 20 properties, each property doesn't store excessive amounts of data
}

public class Database : DbContext
{
    public DbSet<Article> Articles { get; set; }
}

对于for循环中的每个项目,我都这样做:

db.Articles.Add(article);

在for循环之外我做:

db.SaveChanges();

它与我的本地SQLExpress服务器连接,但我想在调用SaveChanges之前没有任何内容,所以我猜服务器不会出现问题....

5 个答案:

答案 0 :(得分:46)

根据Kevin Ramen的评论(3月29日) 我可以确认设置db.Configuration.AutoDetectChangesEnabled = false会对速度产生巨大影响

默认情况下,在2324项上运行Add()在我的机器上运行3分15秒,禁用自动检测导致操作在0.5秒内完成。

http://blog.larud.net/archive/2011/07/12/bulk-load-items-to-a-ef-4-1-code-first-aspx

答案 1 :(得分:19)

我将添加Kervin Ramen的评论说,如果你只是进行插入(没有更新或删除),那么你可以在对上下文进行任何插入之前安全地设置以下属性:

DbContext.Configuration.AutoDetectChangesEnabled = false;
DbContext.Configuration.ValidateOnSaveEnabled = false;

我的工作中有一次性批量导入问题。如果不设置上述属性,则向上下文添加大约7500个复杂对象需要花费30多分钟。设置上述属性(因此禁用EF检查和更改跟踪)会将导入减少到几秒钟。

但是,我再次强调,如果你正在插入,只使用它。如果需要将插入与更新/删除混合,则可以将代码拆分为两个路径,并禁用插入部分的EF检查,然后重新启用对更新/删除路径的检查。我已经成功地使用这种方法来解决慢DbSet.Add()行为。

答案 2 :(得分:9)

工作单元中的每个项目都有开销,因为它必须检查(和更新)身份管理器,添加到各种集合等。

我要尝试的第一件事就是批量打入500组(改变那个数字以适应),每次都从一个新的(新的)对象上下文开始 - 否则你可以合理地期望伸缩性能。将其分成几批也可以防止巨石交易使一切停止。

除此之外; SqlBulkCopy的。它专为大型进口而设计,开销最小。但它不是EF。

答案 3 :(得分:5)

这里有一个非常容易使用和非常快速的扩展: https://efbulkinsert.codeplex.com/

它被称为“实体框架批量插入”。

扩展本身位于名称空间EntityFramework.BulkInsert.Extensions中。因此,使用

显示扩展方法add
using EntityFramework.BulkInsert.Extensions;

然后你可以这样做

context.BulkInsert(entities);

BTW - 如果由于某种原因你不想使用这个扩展,你也可以尝试而不是为每篇文章运行db.Articles.Add(article),每次创建几篇文章的列表然后使用AddRange (EF版本6中的新增功能,以及RemoveRange)将它们一起添加到dbcontext。

答案 4 :(得分:1)

我还没有真正尝试过这个,但我的逻辑是坚持使用ODBC驱动程序将文件加载到datatable中,然后使用sql存储过程将表传递给过程。

对于第一部分,请尝试: http://www.c-sharpcorner.com/UploadFile/mahesh/AccessTextDb12052005071306AM/AccessTextDb.aspx

对于第二部分,请尝试使用SQL过程: http://www.builderau.com.au/program/sqlserver/soa/Passing-table-valued-parameters-in-SQL-Server-2008/0,339028455,339282577,00.htm

在c#中创建SqlCommnand对象并添加到其Parameters集合SqlParameter,即SqlDbType.Structured

嗯,我希望它有所帮助。