C# 使用Distinct和Order By时,实体框架中存在多个查询,性能较差

C# 使用Distinct和Order By时,实体框架中存在多个查询,性能较差,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,EF EFCore v2.2.1中的以下LINQ查询 var x = context.Exchange .Include(q => q.Input) .Where(q => q.InputId != 1&& q.Input.CreatedOnUtc > DateTime.Parse("2019-11-25") && q.

EF EFCore v2.2.1中的以下LINQ查询

    var x = context.Exchange 
            .Include(q => q.Input)
            .Where(q => q.InputId !=  1&& 
                q.Input.CreatedOnUtc > DateTime.Parse("2019-11-25") && 
                q.Input.UserId == 2 && 
                q.BotConversationId == 3)
            .Distinct()
            .OrderBy(q => q.Input.CreatedOnUtc)
            .FirstOrDefault()
最终简化了分析的SQL结果

select * from (
    select distinct e.* 
    from Exchange e, ExchangeInput i 
    where e.InputId = i.InputId
    and e.InputId <> 1
    and i.UserId = 2
    and e.BotConversationId = 3
)

为什么它需要执行两个单独的查询?当ExchangeInput可能有数百万行时,第二个查询非常可怕。 当然,这就足够了:

select * from (
    select distinct e.*, i.CreatedOnUtc 
    from Exchange e, ExchangeInput i 
    where e.InputId = i.InputId
    and e.InputId <> 1
    and i.UserId = 2
    and e.BotConversationId = 3
) a
order by a.CreatedOnUtc 
另外,如我所料,将Distinct放在orderby之后只会给出1个查询


解决这个问题很容易。正在添加。选择。。。在.Distinct之前或删除.Distinct将执行此操作。但是,最初的、性能差的代码在查看时似乎不会立即出现问题

首先,我建议在FirstOrDefault之前调用Distinct是不必要的。当您有OrderBy时,非独立查询中的第一行应始终与独立查询相同!正如您在上一句中提到的,删除Distinct似乎只会创建一个查询

除了你的问题,我还建议在查询之外计算DateTime.Parse2019-11-25。这将允许您将其作为参数传递给数据库服务器,这可能会使您的查询更加高效

总之,我会尝试:

var dateFilter = DateTime.Parse("2019-11-25");
var x = context.Exchange 
        .Include(q => q.Input)
        .Where(q => q.InputId != 1 && 
            q.Input.CreatedOnUtc > dateFilter && 
            q.Input.UserId == 2 && 
            q.BotConversationId == 3)
        .OrderBy(q => q.Input.CreatedOnUtc)
        .FirstOrDefault()

您是对的,不需要使用distinct。我的主要问题是试图理解为什么这种语句会导致如此糟糕的性能,而从LINQ到SQL的转换似乎很简单。
var dateFilter = DateTime.Parse("2019-11-25");
var x = context.Exchange 
        .Include(q => q.Input)
        .Where(q => q.InputId != 1 && 
            q.Input.CreatedOnUtc > dateFilter && 
            q.Input.UserId == 2 && 
            q.BotConversationId == 3)
        .OrderBy(q => q.Input.CreatedOnUtc)
        .FirstOrDefault()