1

我目前正在改进使用实体框架(并且有 4.0 版本)的现有 c# 项目的性能。应用程序中有两种类型的批量操作:

  1. 批量插入
  2. 批量删除

目前它们是使用纯 SQL 语句(“INSERT INTO...”、“DELETE FROM...”)完成的(插入语句本身目前不是批量插入语句,而是“普通”插入语句)。

由于我对 C# 还很陌生,所以我的第一步是看看如果我使用实体框架进行更新和删除,性能会如何。

我的问题是三个折叠:

  1. 如果我尝试使用实体框架进行批量插入,它确实对每个插入的数据行使用 1 个插入,这是真的吗?(因此每个插入都有一个往返)。因此性能低于使用 SQL“插入”?
  2. 这对删除语句也适用吗?
  3. 这里的最佳做法是什么?使用 SQL 语句?还是使用实体框架,或者完全是别的什么?

(对于数据行,我说的是每个 2k-200k 的大小)。

谢谢

4

2 回答 2

2

如果您真的想插入批量数据,您可能想要使用SqlBulkCopy. 您可以在 EF 上下文使用的同一事务中使用它。

EF 不适用于批量操作,您可能会发现它的单行每语句 DML 方法对于大型集合来说过于严格。它强制执行大量往返、大量每个语句的开销,并阻止 SQL Server 一次优化多行的查询计划,这几乎总是比许多小查询更有效(例如 SQL Server 将正确排序所有行,因此索引可以按顺序更新)。

通过使用 EF 进行批量 DML,您基本上可以强制 SQL Server 使用每行 DML 计划。

批量删除可以通过将键批量插入临时表,然后执行连接到该表的删除语句来处理。

于 2012-11-10T13:22:59.617 回答
2

我的问题是三个折叠:

如果我尝试使用实体框架进行批量插入,它确实对每个插入的数据行使用 1 个插入,这是真的吗?(因此每个插入都有一个往返)。因此性能低于使用 SQL“插入”?

是的。如果要使用 EF,请将以下属性设置为 false 以获得更快的性能:

MyContext.Configuration.AutoDetectChangesEnabled = false;
MyContext.Configuration.ValidateOnSaveEnabled = false;

这对删除语句也适用吗?

是的。您也可以在数据库上定义On Delete Cascade,然后数据库将删除引用的实体,因此无需使用 EF 执行此操作。

这里的最佳做法是什么?使用 SQL 语句?还是使用实体框架,或者完全是别的什么?

您可以使用存储过程,在您的 Context 上调用 Query

MyContext.ExecuteStoreQuery("your query")

或者

MyContext.Database.SqlCommand("your query"); 

另一种方法是SaveChanges()在一批(100、200 个标记为已添加或已删除的实体)之后调用,然后释放上下文,以便实体不再附加。然后创建一个新的上下文进行批处理并SaveChanges()再次调用。

更新

我没有使用这种方法,但您可以尝试一下。

用于通用列表的 SqlBulkCopy(对实体框架和 NHibernate 很有用)

下面的可重用通用版本,在 2.4 秒内产生 15k 插入或每秒 +- 6200 行。我在 39 秒内将它增加到 4 个目录,224392 行,速度为 +- 5750 rps(在 4 个文件之间切换)。

于 2012-11-10T13:17:42.720 回答