实体框架批量插入导致选择n + 1问题

时间:2011-07-09 16:50:27

标签: sql-server-2005 entity-framework select

我正在使用Entity Framework将特定对象的多个实例插入到数据库中。我有一个对象上下文,我附加了几个'Product'对象。我插入的对象与数据库中的任何其他表没有任何关系。它纯粹是一个独立的实体。我正在使用'EFProf'工具来分析应用程序。

当我调用'SaveChanges()'将我的'Product'实体持久保存到SQL Server时,EFProf警告我有'Select N + 1'反模式。我不知道这是怎么可能的,因为我只是插入。我对'选择N + 1'的理解是它与低效的对象检索有关。我没有检索任何东西,只插入。

当我检查生成的SQL时,我看到Entity Framework代表我生成了一个select语句,它返回新插入对象的Id。对我插入的每个实体执行此select语句。这可能是选择N + 1问题的原因吗?如果是这样,在单次调用SaveChanges()时插入多个相同类型的实体时,如何避免这种反模式?

生成的SQL如下:

insert [dbo].[Products]
  ([ProductName],
   [ProductNum],
   [Price],
   [EntryDate],
   [Description],
   [Category],
   [UnitsInStock])
values('TestProduct' /* @0 */,
   0 /* @1 */,
   0 /* @2 */,
   '2011-07-09T17:14:49.00' /* @3 */,
   'Category: Test Products - Name TestProduct' /* @4 */,
   'Test Products' /* @5 */,
   0 /* @6 */)


select [Id]
from   [dbo].[Products]
where  @@ROWCOUNT > 0
       and [Id] = scope_identity()

3 个答案:

答案 0 :(得分:1)

你无法避免这种额外的选择。在数据库中使用自动生成的ID并为您正确配置模型后,EF将始终创建此附加选择。

你不需要打扰。使用EF的“批量插入”的性能非常糟糕,因此在每次插入期间的这种额外选择意味着什么。您应该处理的是处理本身,因为EF将为每个插入的记录创建单独的数据库往返,这就是问题所在。如果你真的想将大量的对象传递到数据库中,你想要经常这样做(这不是一次性的工作),你期望一些性能,你应该肯定寻找其他非EF解决方案。例如,已经提到SqlBulkCopy

如果您只是需要在某些操作中插入几个实例,那么就让它成为现实。这就是EF的工作方式。

答案 1 :(得分:0)

使用Entity Framework没有直接支持批量插入。但是,您可以对其进行调整以使用SQLBulkCopyThis MSDN Article is a good example.

答案 2 :(得分:0)

如果您尝试进行批量插入,在我看来SCOPE_IDENTITY()是无用的,因为它存储单个标量值 - 而不是范围。我要背叛我对EF的无知,但它是否将此代码转换为BULK INSERT命令,或SQLBulkCopy,还是其他什么?

如果你打算一次做一次插入,那么首先检查@@ROWCOUNT而不是放入where子句似乎是一个更好的模式:

IF @@ROWCOUNT = 1
BEGIN
    SELECT [Id]
        FROM [dbo].[Products]
        WHERE [Id] = SCOPE_IDENTITY();
END

或者根本没有打扰,因为如果以下结果集为空,您现在知道@@ROWCOUNT是什么:

SELECT [Id]
    FROM [dbo].[Products]
    WHERE [Id] = SCOPE_IDENTITY();