c# - 使用 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 天前。
解决方案
那是因为您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);