【问题标题】:Linq making very inefficient Entity Framework queryLinq 制作非常低效的实体框架查询
【发布时间】:2015-12-20 23:12:48
【问题描述】:

Entity Framework 为以下 LINQ 查询生成性能非常差的 SQL:

var query = _context.Sessions
                    .Where(s => s.OrganizationId == orgId && s.Device != null && s.Device.User != null)
                    .Select(s => s.Device.User)
                    .Distinct();

生成此 SQL:

exec sp_executesql N'SELECT
[Distinct1].[Id] AS [Id], 
[Distinct1].[Email] AS [Email], 
[Distinct1].[Sex] AS [Sex], 
[Distinct1].[Age] AS [Age]
FROM ( SELECT DISTINCT 
    [Extent4].[Id] AS [Id], 
    [Extent4].[Email] AS [Email], 
    [Extent4].[Sex] AS [Sex], 
    [Extent4].[Age] AS [Age]
    FROM   (SELECT [Extent1].[OrganizationId] AS [OrganizationId], [Extent3].[UserId] AS [UserId1]
        FROM   [dbo].[Sessions] AS [Extent1]
        INNER JOIN [dbo].[Devices] AS [Extent2] ON [Extent1].[DeviceId] = [Extent2].[Id]
        LEFT OUTER JOIN [dbo].[Devices] AS [Extent3] ON [Extent1].[DeviceId] = [Extent3].[Id]
        WHERE [Extent2].[UserId] IS NOT NULL ) AS [Filter1]
    LEFT OUTER JOIN [dbo].[Users] AS [Extent4] ON [Filter1].[UserId1] = [Extent4].[Id]
    WHERE [Filter1].[OrganizationId] = @p__linq__0
)  AS [Distinct1]',N'@p__linq__0 int',@p__linq__0=2

我实际上要执行的 SQL 如下,它运行得很快:

select distinct u.*
from Sessions s
inner join Devices d on s.DeviceId = d.Id
inner join Users u on d.UserId = u.Id
where OrganizationId = 2

如何让实体框架生成的 SQL 尽可能接近这个查询?

【问题讨论】:

  • 看来你需要.Select(s => s.Device.User.Email)
  • 这些不是等效的查询,所以难怪它们的执行方式会有所不同。
  • 最后一个(已编辑的)SQL 查询如何执行?
  • 能否确认编辑后手动SQL查询还是很快的?
  • 我随身携带了一位经验丰富的 DBA 的明智建议,该建议至少已被我多次证明。如果您的查询中有 DISTINCT,则说明有问题。这个查询可以用不同的方式进行,不需要 DISTINCT。

标签: c# entity-framework linq linq-to-entities


【解决方案1】:

如果您只想要电子邮件,为什么要选择整个 User 实体?

试试这个:

var query = _context.Sessions
                    .Where(s => s.OrganizationId == orgId && s.Device != null && s.Device.User != null)
                    .Select(s => s.Device.User.Email)
                    .Distinct();

【讨论】:

  • 我更正了我的问题,以反映我正在寻找不同的用户记录,而不仅仅是不同的 User.Email。
  • 是什么让用户与众不同?所有领域结合起来?还是只是一些主键值?
  • 我最初的问题很糟糕,没有提出正确的问题。我更正了。
【解决方案2】:

尝试从用户表开始:

var query = (
    from u in _context.Users
    where u.Devices.Any(d => d.Sessions
        .Any(s => s.OrganisationId == orgId)
    )
    select u
);

它不会执行您指定的查询,但它返回的内容可能具有相同的良好性能。

【讨论】:

  • 我也是这么想的。以我的经验,这甚至可能比原始的 sql 查询更好。 +1
  • 这极大地提高了查询的性能。很好的解决方案。
【解决方案3】:

你可以很简单地做到这一点:

_context.Sessions
    .Where(s => s.OrganizationId == 2)
    .Select(s => s.Device.User)
    .Distinct();

您无需检查null,因为它会为您执行INNER JOIN

【讨论】:

    【解决方案4】:

    我不喜欢使用 DISTINCT ,如果查询包含它,则查询错误。

    其他方法

    var query = _context.Sessions.Include("Device.User.Email")
                        .Where(s => s.OrganizationId == orgId);
    

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 2011-06-29
      • 1970-01-01
      相关资源
      最近更新 更多