EF Core 操作PostgreSQL:同查询原生SQL性能远超LINQ查询
兄弟,你已经精准揪出了问题的两个关键异常点,这正是导致6秒性能差距的根本原因!咱们把这事儿掰碎了说:
1. 为什么EF Core拉取了全量字段?
你的LINQ查询里写的是group new { oolk, oool } by oolk.Salesrep——这里你把整个Oolookup和Ooorderlines实体对象都塞进了分组的匿名类里。EF Core没办法推断出你其实只需要oolk.Salesrep和oool.Openqty,只能老老实实把这两个表的所有字段都查出来,直接导致了大量不必要的数据从数据库传输到客户端,光是数据量就比原生SQL大了好几倍。
2. 为什么求和在客户端执行?
同样是因为分组的是完整实体组合,EF Core无法将g.Sum(gr => gr.oool.Openqty)这个聚合操作转换为数据库端的SUM()函数。它只能先把所有符合条件的行全部加载到客户端内存里,再在内存里做分组和求和计算——这相当于把数据库的计算压力转移到了你的应用程序,还要传输海量冗余数据,性能能不崩嘛!
修复后的LINQ查询代码
要解决这个问题,你需要明确告诉EF Core:只需要分组Salesrep,只聚合Openqty,不需要其他字段。修改后的代码如下:
(from oolk in db.Oolookup join oool in db.Ooorderlines on oolk.Orderlinekey equals oool.Orderlinekey where oolk.Salesteam == "Team1" && oolk.Categorycode == "Category 8" // 只把需要聚合的字段放进分组,而非整个实体 group oool.Openqty by oolk.Salesrep into g select new { SalesRep = g.Key, // 直接对分组后的数值求和,EF会转换为数据库的SUM() OpenQty = g.Sum() }).ToList()
修改后,EF Core生成的SQL会和你手写的原生SQL几乎一致:只查询oolk.salesrep和SUM(oool.openqty),在数据库端完成分组和聚合计算,数据传输量骤降,性能自然就和原生SQL看齐了。
额外提醒
EF Core的查询转换非常依赖你构建的查询结构,永远不要在分组/投影中包含完整的实体对象,除非你确实需要所有字段。只选择你需要的字段,才能让EF生成高效的SQL,充分利用数据库的计算能力。
内容的提问来源于stack exchange,提问作者Justin Capalbo

