实体框架性能:联接 vs 导航属性

6
我正在尝试理解为什么在我的情况下,使用连接操作比使用导航属性的语句更快。我有两个查询。
第一个查询使用导航属性:
          var result = (from users in context.MetricBloodPreasure
                orderby users.User.LastName, users.User.FirstName
                select new
                {
                    UserName = users.User.LastName + ", " + users.User.FirstName,
                    Date = users.DateOfValue,
                }).ToList();

生成的 SQL:
SELECT 
    [Project1].[C1] AS [C1], 
    [Project1].[C2] AS [C2], 
    [Project1].[DateOfValue] AS [DateOfValue]
    FROM ( SELECT 
        [Extent1].[DateOfValue] AS [DateOfValue], 
        [Extent2].[FirstName] AS [FirstName], 
        [Extent2].[LastName] AS [LastName], 
        1 AS [C1], 
        CASE WHEN ([Extent2].[LastName] IS NULL) THEN N'' ELSE [Extent2].[LastName] END + N', ' + CASE WHEN ([Extent2].[FirstName] IS NULL) THEN N'' ELSE [Extent2].[FirstName] END AS [C2]
        FROM  [dbo].[MetricBloodPreasure] AS [Extent1]
        INNER JOIN [dbo].[User] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
    )  AS [Project1]
    ORDER BY [Project1].[LastName] ASC, [Project1].[FirstName] ASC

使用join方法的第二种方式:

var result1 = (from u in context.User
                orderby u.LastName, u.FirstName
                join us in context.MetricBloodPreasure
                    on u.Id equals us.UserId into users
                from s in users
                select new
                {
                    UserName = s.User.LastName + ", " + s.User.FirstName,
                    Date = s.DateOfValue,
                }).ToList();

生成的 SQL:

SELECT 
    1 AS [C1], 
    CASE WHEN ([Extent1].[LastName] IS NULL) THEN N'' ELSE [Extent1].[LastName] END + N', ' + CASE WHEN ([Extent1].[FirstName] IS NULL) THEN N'' ELSE [Extent1].[FirstName] END AS [C2], 
    [Extent2].[DateOfValue] AS [DateOfValue]
    FROM  [dbo].[User] AS [Extent1]
    INNER JOIN [dbo].[MetricBloodPreasure] AS [Extent2] ON ([Extent1].[Id] = [Extent2].[UserId]) AND ([Extent2].[UserId] = [Extent1].[Id])

在运行第一个查询之前,请调用var user = context.User.FirstOrDefault();,因为我认为打开到数据库的连接需要一些时间。
结果: 导航属性查询:00:00:00.6719646 联接查询:00:00:00.4941169
从结果来看,似乎使用联接而不是导航属性的Linq查询更快。这是真的还是我做错了什么?

你需要在查询之间从数据库中清除缓存以获取正确的结果,因为你正在调用ToList()。将查询构建与物化分开,并对其进行基准测试。 - Janne Matikainen
第二个查询似乎没有考虑OrderBy。这可能是差异的原因,您可以尝试...from s in users orderby u.LastName, u.FirstName... - jbl
1个回答

2
为了更好地了解它正在做什么,您应该获取原始SQL并自行检查执行计划。
要做到这一点,您可以使用SQL Profiler来查看正在运行的查询,或者在运行查询之前执行以下操作之类来记录SQL查询本身:
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

仅仅运行一次每个测试并进行简单的基准测试并不一定可靠。您需要多次运行并平均结果。您还应该以相反的顺序运行它们,以查看是否会改变结果。


此外,将更多的数据插入到数据库中是一个好主意,这应该会突出显示差异(如果存在)。 - Marcin J
两个查询都返回了超过9000行......是的,我使用日志并且在我的数据库上下文中使用新实例运行查询。但连接仍然更快。 - puko
你能把正在运行的SQL贴到原问题中吗?此外,你是否在SSMS中运行了SQL并打开了执行计划,以便你可以看到差异在哪里? - Jeff Treuting

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接