c# - 使用 Distinct 和 Order By 时实体框架中的多个查询和较差的性能
问题描述
EF 中的以下 LINQ 查询(EFCore,v2.2.1)
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
)
select * from ExchangeInput
为什么需要做两个单独的查询?当 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 放在 order by 之后只给出 1 个查询。
解决问题很容易。.Select(...)
在 the 之前添加 a.Distinct
或删除 the.Distinct()
即可。但最初的、性能不佳的代码在审查时似乎并没有立即出现问题。
解决方案
我首先建议Distinct()
在 a 之前调用FirstOrDefault()
是不必要的。当您有 OrderBy 时,“非独特”查询中的第一行应始终与“独特”查询相同!正如您在上一句中提到的,似乎删除Distinct()
应该只创建一个查询。
除了您的问题,我还建议DateTime.Parse("2019-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()
推荐阅读
- python - 熊猫,删除最后一个'_'之后的所有内容
- jquery - 基于两个单选按钮显示和隐藏 div
- c - 不理解带有 switch 块的程序的输出
- web-component - Web 组件 - 包装子元素
- python - 在与 source 同级的目录中运行测试
- android - 为什么我的 GlideApp 不适用于 gsReference (Firebase + Kotlin)
- reactjs - 尝试使用 React-bootstrap InputGroup 时获取“元素类型无效:预期为字符串 (...)”
- sql - 如何计算行数以使连续出现的数据计为 1?
- python - 如何在 Python 3 中将文本复制到系统剪贴板
- vue.js - Vue.js 使用模板中调用的方法的返回值