4

我们正在尝试优化我们的一些方法。我们使用 Redgate 的性能分析器来查找一些性能漏洞。

我们的工具以多种方法使用 Linq 对象。但是我们注意到 aFirstOrDefault对 +/- 1000 个对象的集合需要很长时间。

探查器还会提醒查询非常慢。我已经添加了带有分析器结果的图像。

无法将集合添加到数据库然后查询数据库。有什么建议吗?

谢谢 !

private SaldoPrivatiefKlantVerdeelsleutel GetParentSaldoPrivatiefKlantVerdeelsleutel(SaldoPrivatiefKlantVerdeelsleutel saldoPrivatiefKlantVerdeelsleutel, SaldoGebouwRekeningBoeking boeking, int privatiefKlant)
{
    SaldoPrivatiefKlantVerdeelsleutel parentSaldoPrivatiefKlantVerdeelsleutel = null;

    if (saldoPrivatiefKlantVerdeelsleutel != null)
    {
        try
        {
            parentSaldoPrivatiefKlantVerdeelsleutel = saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode.SaldoPrivatiefKlantVerdeelsleutelCollection
                .FirstOrDefault(s => (boeking == null || (s.SaldoVerdeelsleutel != null &&
                (s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID)))
                && s.PrivatiefKlant.ID == privatiefKlant);
        }
        catch (Exception ex)
        { }
    }

    return parentSaldoPrivatiefKlantVerdeelsleutel;
}

图片: 简介报告

4

4 回答 4

7

您应该能够通过将其重写为来加速它

saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode.SaldoPrivatiefKlantVerdeelsleutelCollection
            .Where(s => (boeking == null || (s.SaldoVerdeelsleutel != null &&
                (s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID))) && s.PrivatiefKlant.ID == privatiefKlant)
            .FirstOrDefault()

请参阅为什么 LINQ .Where(predicate).First() 比 .First(predicate) 快?为什么这更快。

于 2013-08-30T13:14:45.230 回答
2

FirstOrDefault对源集合执行标准线性搜索并返回与谓词匹配的第一个元素。这是O(n),因此在更大的集合上花费更多时间也就不足为奇了。

您可以尝试跟随,但收益不会很大,因为它仍然是O(n)

private SaldoPrivatiefKlantVerdeelsleutel GetParentSaldoPrivatiefKlantVerdeelsleutel(SaldoPrivatiefKlantVerdeelsleutel saldoPrivatiefKlantVerdeelsleutel, SaldoGebouwRekeningBoeking boeking, int privatiefKlant)
{
    SaldoPrivatiefKlantVerdeelsleutel parentSaldoPrivatiefKlantVerdeelsleutel = null;

    if (saldoPrivatiefKlantVerdeelsleutel != null)
    {
        try
        {
            var query = saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode
                                                         .SaldoPrivatiefKlantVerdeelsleutelCollection
                                                         .Where(s => s.PrivatiefKlant.ID == privatiefKlant);

            if(boeking != null)
            {
                var gebouwVerdeelSleutelId = boeking.SaldoGebouwRekeningVerdeling
                                                    .SaldoGebouwRekening
                                                    .SaldoVerdeelsleutel
                                                    .GebouwVerdeelSleutel
                                                    .ID;

                query = query.Where(s => s.SaldoVerdeelsleutel != null &&
                    s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == gebouwVerdeelSleutelId);
            }
            parentSaldoPrivatiefKlantVerdeelsleutel = query.FirstOrDefault();
        }
        catch (Exception ex)
        { }
    }

    return parentSaldoPrivatiefKlantVerdeelsleutel;
}

它会变得更好,因为boeking != null检查只会进行一次,而不是在每个源集合元素上。并且因为嵌套Where调用是组合在一起的,它们不会导致性能损失。

于 2013-08-30T13:17:52.840 回答
2

我会说这个

boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID

可能是罪魁祸首。尝试将其缓存在外部,例如:

var id = boeking != null ? boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID : 0;

并使用id查询内部。

(我在做一个假设:长链的一个属性做了一些“不太聪明”的事情,实际上很慢)

于 2013-08-30T13:20:30.793 回答
0

你可以试着把它写成一个简单的代码。LINQ 正在使用委托,这就是为什么会有一点性能影响。

                try
                {
                    parentSaldoPrivatiefKlantVerdeelsleutel = null;
                    foreach (var s in saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode.SaldoPrivatiefKlantVerdeelsleutelCollection)
                    {
                        if ((boeking == null || (s.SaldoVerdeelsleutel != null && (s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID))) && s.PrivatiefKlant.ID == privatiefKlant)
                        {
                            parentSaldoPrivatiefKlantVerdeelsleutel = s;
                            break;
                        }
                    }
                }
                catch (Exception ex)
                { }
于 2013-08-30T13:43:55.330 回答