【问题标题】:Why is my Entity Framework query with Single slow?为什么我的单一实体框架查询很慢?
【发布时间】:2014-05-07 13:05:04
【问题描述】:

我有一个非常简单的查询,非常慢。 Entity Framework Profiler 表示大约需要 100 毫秒。

dbContext.Users.Single(u => u.Id == userId);

经过一番尝试,我发现了一个非常相似但速度更快(大约 3 毫秒)的查询。

dbContext.Users.Where(u => u.Id == userId).ToList().Single();

当我比较两个查询的 sql 时,第二个查询不使用嵌套的 SELECT 并且没有 TOP 操作。但我不希望它仅仅因为这两件事而快 30 倍。此外,当使用 SQL Server Management Studio 执行查询时,没有可测量的差异。

当我查看执行计划时,它们都进行了聚集索引查找,查询成本为 100%。而额外的 select 和 Top 操作的查询成本为 0%。 来自 EFProfiler 的查询计划表示相同,表明它不应该有任何区别。

如何才能更好地了解这种情况下的查询性能?

下面是第一个查询的结果 SQL。

SELECT [Limit1].[Id]                     AS [Id],
   [Limit1].[EmailAddress]           AS [EmailAddress],
   [Limit1].[FirstName]              AS [FirstName],
   [Limit1].[LastName]               AS [LastName]
FROM   (SELECT TOP (2) [Extent1].[Id]                     AS [Id],
                   [Extent1].[EmailAddress]           AS [EmailAddress],
                   [Extent1].[FirstName]              AS [FirstName],
                   [Extent1].[LastName]               AS [LastName]
    FROM   [dbo].[Users] AS [Extent1]
    WHERE  ([Extent1].[Id] = 'b5604f88-3e18-42a5-a45e-c66cc2a632d3' /* @p__linq__0 */)
           AND ('b5604f88-3e18-42a5-a45e-c66cc2a632d3' /* @p__linq__0 */ IS NOT NULL))    AS [Limit1]

这里是第二个(更快)查询的 sql。

SELECT [Extent1].[Id]                     AS [Id],
   [Extent1].[EmailAddress]           AS [EmailAddress],
   [Extent1].[FirstName]              AS [FirstName],
   [Extent1].[LastName]               AS [LastName]
FROM   [dbo].[Users] AS [Extent1]
WHERE  ([Extent1].[Id] = 'b5604f88-3e18-42a5-a45e-c66cc2a632d3' /* @p__linq__0 */)
   AND ('b5604f88-3e18-42a5-a45e-c66cc2a632d3' /* @p__linq__0 */ IS NOT NULL)

【问题讨论】:

  • 您也可以在第二个示例中省略 ToList() 调用。 Single()枚举查询。只需保留 Where() 子句即可。
  • .Single() 需要返回的“top 2”结果来确定是否存在单个匹配项。结果中的一行表示成功,两行或零行表示“.Single()”失败并且应该抛出错误。在您的第二个示例中,“.ToList()”导致查询在应用“.Single()”之前执行。查询可以返回任意数量的结果,.Single() 方法将应用于 List 结果。
  • 您是否在同一个应用程序中尝试这两个查询,如果是这样,是实体框架在您的应用程序中进行的第一个查询中的两个中较慢的吗?实体框架对于每个应用程序域的每个数据库执行的第一个查询来说是一个非常重要的开销,即使对象被释放,它也会重用它在第一个查询之后构建的缓存元数据,但是第一个查询将会很多较慢(稍后在程序中第二次运行相同的查询,您将看到速度显着变化)
  • @Towa 我很惊讶 GUID 上的聚集索引并没有降低性能
  • @Jaycee:很可能是这样,但也可能是他的表很小,所以如果有的话,它的分页并不多……GUID 会造成错误的主键……

标签: sql sql-server performance entity-framework database-performance


【解决方案1】:

您真正想要的是dbContext.Users.Find(id) - 如果不需要,它甚至不会进入数据库。在msdn 上查看更多详细信息。

【讨论】:

  • +1 告诉我有关 Find() 的信息。我以前不知道这一点。但在这种特殊情况下,它会生成与 Single 相同的 SQL,并且性能也相同(差)。
【解决方案2】:

当你说

dbContext.Users.Single(u => u.Id == userId);

Users 是 DbSet 类型或其用户集合,因此它首先在
dbContext.Users.Where(u => u.Id == userId).ToList().Single(); 中获取用户集合 它包含加载它的条件。

所以如果有 100 个用户 第一个查询将获取 100 个用户,然后进行过滤,而在第二个查询中它只会获取 1 个。

希望这会有所帮助。

【讨论】:

  • Anshul,第一个查询将只返回数据库中与该用户 ID 匹配的前两个用户。它不会获取所有 100 个用户。即使有 100 个具有该用户 ID 的用户。第二个将返回与该用户 ID 匹配的所有用户,然后在内存中将应用单一方法。
  • 为什么不在stackoverflow上问你的问题(但不同的线程)? :)
猜你喜欢
  • 2014-12-13
  • 2023-03-05
  • 1970-01-01
  • 2022-01-01
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多