首页 > 解决方案 > 使用 Entity Framework 的简单请求的大量执行时间

问题描述

我有一个来自 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 数据库上。此外,这个问题出现在 4 或 5 天前。

标签: c#sql.netentity-frameworkentity-framework-6

解决方案


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

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

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

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

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

编辑 :

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

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);

推荐阅读