【问题标题】:Big execution time for a simple request with Entity Framework使用 Entity Framework 的简单请求的大量执行时间
【发布时间】:2019-01-23 14:19:08
【问题描述】:

我有一个来自 Entity Framework 6 的奇怪行为。我有一个简单的(一个简单的 where 和一个简单的选择)查询,需要 30 秒。

我使用 Sql Profiler 来观察执行了哪些 sql 代码。我正在使用 Where 然后 FirstOrDefault 方法来获取项目。然后我尝试了另一个查询,我做了一个 ToList(获取数据)然后是 FirstOrDefault,它需要不到 1 秒。

Original code (takes 30s to be executed):
-----------------------------------------

id = Container.SocialNetworks.Where(a => a.SocialNetwork == EnumSocialNetwork.LinkedIn && a.Link == linkedinurl && a.User.TenantID == Container.TenantId).Select(i => i.UserID).FirstOrDefault();

From SQL Profiler :
-------------------

exec sp_executesql N'SELECT 
    [Limit1].[UserID] AS [UserID]
    FROM ( SELECT TOP (1) 
        [Extent1].[UserID] AS [UserID]
        FROM  [dbo].[SocialNetworks] AS [Extent1]
        INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserID] = [Extent2].[ID]
        WHERE (0 = [Extent1].[SocialNetwork]) AND (([Extent1].[Link] = @p__linq__0) OR (([Extent1].[Link] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Extent2].[TenantID] = @p__linq__1)
    )  AS [Limit1]',N'@p__linq__0 nvarchar(4000),@p__linq__1 int',@p__linq__0=N'linkedin.com/in/a-profile',@p__linq__1=5

After testing another solutions (takes less than 1s):
-----------------------------------------------------

id = Container.SocialNetworks.Where(a => a.SocialNetwork == EnumSocialNetwork.LinkedIn && a.Link == linkedinurl && a.User.TenantID == Container.TenantId).Select(i => i.UserID).ToList().FirstOrDefault();

From SQL Profiler:
------------------

exec sp_executesql N'SELECT 
    [Extent1].[UserID] AS [UserID]
    FROM  [dbo].[SocialNetworks] AS [Extent1]
    INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserID] = [Extent2].[ID]
    WHERE (0 = [Extent1].[SocialNetwork]) AND (([Extent1].[Link] = @p__linq__0) OR (([Extent1].[Link] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Extent2].[TenantID] = @p__linq__1)',N'@p__linq__0 nvarchar(4000),@p__linq__1 int',@p__linq__0=N'linkedin.com/in/a-profile-as',@p__linq__1=5

如您所见,我使用 ToList 在使用 FirstOrDefault 过滤之前获取数据。而且,通常不建议执行 ToList,即急切加载。为什么实体框架在我使用 FirstOrDefault 时将选择放入选择中?

我的英语很抱歉,我希望我能正确解释我的问题。

编辑:

我有一些有趣的事情要补充,当“linkedinurl”值不存在时,并且只有当它不存在时,在数据库中,两个查询都需要不到 1 秒的时间。

编辑 2:

写完评论后,我想补充一点,我们的数据库在 Azure 上。并且问题不会出现在简单的 SQLEXPRESS 数据库上。而且,这个问题出现在四五天前。

【问题讨论】:

  • 您的第二个查询应该比第一个查询花费更多的时间,因为它将所有数据加载到内存中,然后再取一个。看起来太诡异了。您确定第一个查询需要更多时间吗?
  • 如果你只读取数据,你应该使用 AsNoTracking()
  • @OfficalMesut 那是另一回事!问题是为什么第一次查询像 OP 所说的那样花费这么多时间?
  • 真的,我可以向您保证,第一个示例需要 30 秒(使用单个 FirstOrDefault,没有 ToList)...这就是为什么它很奇怪! AsNoTracking 允许我获取 Id ?
  • 您是否因此在单个应用程序运行中运行这些查询?您是否尝试在 2 个应用程序运行中分别运行查询?您也可以尝试以相反的顺序运行,看看会发生什么。

标签: c# sql .net entity-framework entity-framework-6


【解决方案1】:

那是因为您在where().Select() 组合之后使用了FirstOrDefault

第一个查询会像这样更好地工作:

id = Container.SocialNetworks.FirstOrDefault(a => a.SocialNetwork == EnumSocialNetwork.LinkedIn && a.Link == linkedinurl && a.User.TenantID == Container.TenantId)?.UserID;

如您所见,我使用 FirstOrDefault 就像您使用 Where 一样,但这将加载整个对象,如 cmets 中所述。

为什么你的第二个查询更快?因为您以 ToList() 结束了查询,所以 FirstOrDefault 部分仅适用于您的 c# 代码,在加载行之后,而不是通过双选在 DB 上。

编辑:

尝试这两行可能会更好地突出根本原因:

1.尝试订购您的套装:

id = Container.SocialNetworks
   .Where(a => a.SocialNetwork == EnumSocialNetwork.LinkedIn && a.Link == linkedinurl && a.User.TenantID == Container.TenantId)
   .OrderBy(t => t.UserID).Select(i => i.UserID).FirstOrDefault();

2。使用聚合函数:

id = Container.SocialNetworks
    .Where(a => a.SocialNetwork == EnumSocialNetwork.LinkedIn && a.Link == linkedinurl && a.User.TenantID == Container.TenantId)
    .Min(i => i.UserID);

【讨论】:

  • 非常感谢您的解释,但是当您使用 FirstOrDefault 时,您无法选择之后的单个列。我尝试了您的代码行,但无法编译,因为 FirstOrDefault 不返回 IQueryable,而是返回整个 Object (T)。
  • 应该是id = Container.SocialNetworks.Select(i => i.UserID).FirstOrDefault(a => a.SocialNetwork == EnumSocialNetwork.LinkedIn && a.Link == linkedinurl && a.User.TenantID == Container.TenantId);
  • collection.Where(predicate).First()collection.First(predicate)没有区别。
  • 您的解决方案的问题是您将加载整个实体,而不仅仅是像作者那样加载UserId
  • @AntoinePelletier 非常感谢,但没有...Linq 的结果相同(~30s 执行时间)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多