在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。

在Linq到实体中是否有一种有效的中间计算方法?

在查询上执行的.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)
相关文章: