在Linq到实体中是否有一种有效的中间计算方法?
本文关键字:有效 一种 中间 方法 计算 实体 Linq 是否 | 更新日期: 2023-09-27 18:15:12
我有这个查询,它在幕后使用了LinqToEntities
(...)
.GroupBy(x => x.FahrerID)
.Select(x => new FahrerligaEintrag()
{
FahrerID = x.Key,
FahrerFullName = string.Empty,
VollgasKmAufHundertKm = (100m / x.Sum(y => y.BasisMeter)) * (x.Sum(y => y.Gas100ProzentInMeter.Value) + x.Sum(y => y.Gas90ProzentInMeter.Value)),
LeerlaufInProzent = (100m / x.Sum(y => y.BasisSekunden)) * x.Sum(y => y.LeerlaufInSekunden.Value),
VerbrauchLiterAufHundertKm = (100m / x.Sum(y => y.BasisMeter)) * x.Sum(y => y.VerbrauchInLiter.Value) * 1000,
RollenKmAufHundertKm = (100m / x.Sum(y => y.BasisMeter)) * x.Sum(y => y.RollenInMeter.Value),
TempomatKmAufHundertKm = (100m / x.Sum(y => y.BasisMeter)) * x.Sum(y => y.TempomatInMeter.Value),
GeschwindigkeitsuebertretungenAnzahlAufHundertKm = (100m / x.Sum(y => y.BasisMeter)) * 1000 * x.Sum(y => y.UebertretungenAnzahl.Value),
GangwechselAnzahlAufHundertKm = (100m / x.Sum(y => y.BasisMeter)) * 1000 * x.Sum(y => y.GangwechselAnzahl.Value)
});
可以看到这部分重复了几次(100m/x.m um(y => y.BasisMeter)).
在Linq to Objects中,我们会很自然地首先进入一个匿名类来计算因子,以避免重复计算。这样的:
.GroupBy(x => x.FahrerID)
.Select(x => new
{
Grouping = x,
BasisMeterFaktor = 100m / x.Sum(y => y.BasisMeter),
BasisSekundenFaktor = 100m /x.Sum(y => y.BasisSekunden)
})
.Select(x => new FahrerligaEintrag()
{
FahrerID = x.Grouping.Key,
FahrerFullName = string.Empty,
VollgasKmAufHundertKm = x.BasisMeterFaktor * (x.Grouping.Sum(y => y.Gas100ProzentInMeter.Value) + x.Grouping.Sum(y => y.Gas90ProzentInMeter.Value)),
LeerlaufInProzent = x.BasisSekundenFaktor * x.Grouping.Sum(y => y.LeerlaufInSekunden.Value),
VerbrauchLiterAufHundertKm = x.BasisMeterFaktor * x.Grouping.Sum(y => y.VerbrauchInLiter.Value) * 1000,
RollenKmAufHundertKm = x.BasisMeterFaktor * x.Grouping.Sum(y => y.RollenInMeter.Value),
TempomatKmAufHundertKm = x.BasisMeterFaktor * x.Grouping.Sum(y => y.TempomatInMeter.Value),
GeschwindigkeitsuebertretungenAnzahlAufHundertKm = x.BasisMeterFaktor * 1000 * x.Grouping.Sum(y => y.UebertretungenAnzahl.Value),
GangwechselAnzahlAufHundertKm = x.BasisMeterFaktor * 1000 * x.Grouping.Sum(y => y.GangwechselAnzahl.Value)
});
然而,在LinqToEntities中,这会导致性能较差的SQL代码。至少对于我使用的这个Oracle后端(我无法对其进行分析以实际显示SQL)。所以,我想知道是否有其他方法可以避免重复计算,或者这只是我能得到的最快的方法。
请原谅所有这些德语变量名。我相信你还是明白意思的。
我能够按照建议使用ToTraceString()。有趣的是,投影的SQL包含18个(!!)SELECT语句。没有它,它只包含2。
在查询上执行的.ToTraceString()
是否提供了一个可以分析的SQL查询?在所有这些计算中很容易迷失方向,但我确信,如果您想在单个查询中进行所有这些计算,那么性能将受到影响。另一种减少计算重复的方法是使用let
关键字(没有针对它的扩展方法,因此您必须使用"传统"LINQ)。这"允许"您分配一个可以在查询中重用的变量。但我怀疑它是否会比你的分组方法更好。
from f in Fahrer
let meterFaktor = 100m / x.Sum(y =>.BasisMeter)
select new FahrerLigaEintrag()
{
...
}
我想我应该在这里加上这一点,而不是直接在twitter上给Christoph。我认为这对LINQ来说是一个很大的要求。是的,这是可以做到的,但正如他所看到的,这并不漂亮,因为LINQ到实体必须使用通用算法来处理你扔给它的任何东西。如果他有可能向数据库添加存储过程或视图,我就会走那条路。
我还建议(最好我能在140个字符),他检查EFProfiler (efprof.com)或LLBLGen的新profiler (llblgen.com)分析EF查询在Oracle
使用通用委托Func<Tx, Ty, TResult>
如何?
// declare out of query and provide valid types for x, y, result
Func<TX, TY, TResult> basisMeterFaktorAlgo;
// set formula once
basisMeterFaktorAlgo = (x, y) => 100m / x.Sum(y => y.BasisMeter);
// call it in query
basicMeterFactor = basisMeterFaktorAlgo(xValue, yValue)