c# - 如何在 Linq 中提高此查询性能?

标签 c# performance linq

我有一个大表,想知道是否可以提高查询性能。

allDocumentsWithPersianMonth25000000 记录

    var normalDocuments = allDocumentsWithPersianMonth.Where(x => x.DocumentTypeId != 8 && x.DocumentTypeId != 9);
    var debitOpening = allDocumentsWithPersianMonth.Where(x => x.DocumentTypeId == 8);
    var creditOpening = allDocumentsWithPersianMonth.Where(x => x.DocumentTypeId == 8);
    var debitClosing = allDocumentsWithPersianMonth.Where(x => x.DocumentTypeId == 9);
    var creditClosing = allDocumentsWithPersianMonth.Where(x => x.DocumentTypeId == 9);

    return allDocumentsWithPersianMonth
        .GroupBy(x => new { x.DetailId, x.DetailCode, x.DetailDescription, x.PersianMonth })
        .Select(g => new AccountsAgingViewModel
        {
            DetailId = g.Key.DetailId,
            DetailCode = g.Key.DetailCode,
            DetailDescription = g.Key.DetailDescription,
            FarvardinDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 1).Sum(x => x.Debit),
            OrdibeheshtDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 2).Sum(x => x.Debit),
            KhordadDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 3).Sum(x => x.Debit),
            TirDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 4).Sum(x => x.Debit),
            MordadDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 5).Sum(x => x.Debit),
            ShahrivarDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 6).Sum(x => x.Debit),
            MehrDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 7).Sum(x => x.Debit),
            AbanDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 8).Sum(x => x.Debit),
            AzarDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 9).Sum(x => x.Debit),
            DeyDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 10).Sum(x => x.Debit),
            BahmanDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 11).Sum(x => x.Debit),
            EsfandDebit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 12).Sum(x => x.Debit),
            FarvardinCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 1).Sum(x => x.Credit),
            OrdibeheshtCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 2).Sum(x => x.Credit),
            KhordadCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 3).Sum(x => x.Credit),
            TirCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 4).Sum(x => x.Credit),
            MordadCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 5).Sum(x => x.Credit),
            ShahrivarCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 6).Sum(x => x.Credit),
            MehrCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 7).Sum(x => x.Credit),
            AbanCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 8).Sum(x => x.Credit),
            AzarCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 9).Sum(x => x.Credit),
            DeyCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 10).Sum(x => x.Credit),
            BahmanCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 11).Sum(x => x.Credit),
            EsfandCredit = normalDocuments.Where(x => x.DetailId == g.Key.DetailId && x.PersianMonth == 12).Sum(x => x.Credit),
            DebitSumOpening = debitOpening.Where(y => y.DetailId == g.Key.DetailId).Sum(x => x.Debit),
            DebitSumClosing = debitClosing.Where(y => y.DetailId == g.Key.DetailId).Sum(x => x.Credit),
            CreditSumOpening = creditOpening.Where(y => y.DetailId == g.Key.DetailId).Sum(x => x.Debit),
            CreditSumClosing = creditClosing.Where(y => y.DetailId == g.Key.DetailId).Sum(x => x.Credit),
        })

    .ToList();

最佳答案

您应该首先消除相同查询的执行。例如检查以下方法。我们不是每个月都迭代 normalDocuments,而是只迭代一次并根据月份对文档进行分组。 然后我们创建一个字典,键为 PersianMonth 并为 Debit 的相应总和赋值。

这样做,我们将从 24 次迭代变为仅 1 次迭代。然后我们定义一个函数以从该字典中获取一个月的借方或贷方值。根据您的模型,存款可能是借方或贷方。因此,通过传递 bool 参数 isDebit,您可以确定是要读取 Debit 还是 Credit 的值。

这个定义可能需要一些改变,因为我不知道DebitCredit的类型,我只是假设这是一个十进制数

 .Select(g => 
 {
     var groupedDocuments = normalDocuments
                                .Where(x => x.DetailId == g.Key.DetailId)
                                .GroupBy(x => x.PersianMonth)
                                .ToDictionary(x => x.Key, 
                                              x => new DepositTypes(x.Sum(y=>y.Debit), x.Sum(y=>y.Credit));

     Func<int, bool, decimal> getValueFunc = (id, isDebit) 
         => groupedDocuments.TryGetValue(id, out var value) 
                ? (isDebit ? value.Debit ?? value.Credit) 
                : 0;

     return new AccountsAgingViewModel
     {
        DetailId = g.Key.DetailId,
        DetailCode = g.Key.DetailCode,
        DetailDescription = g.Key.DetailDescription,
        FarvardinDebit = getValueFunc(1, isDeposit: true);
        OrdibeheshtDebit = getValueFunc(2, isDeposit: true);
        // etc.
     };
}

private class DepositTypes
{
    public decimal Debit { get; }
    public decimal Credit {get; }

    public DepositTypes(decimal debit, decimal credit)
    {
        Debit = debit;
        Credit = credit;
    }
}

关于c# - 如何在 Linq 中提高此查询性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50830487/

相关文章:

c# - LINQ multiple join IQueryable 修改结果选择器表达式

c# - 从内部取消延续链

c# - 在 C# 中以编程方式终止 vista/windows 7 中的进程

python-3.x - 提高具有多个条件的 Pandas 子集/过滤器的性能

Django 请求非常慢,找不到原因

c# - parallel linq : AsParallel(). forAll() 使某些对象为空

c# - Linq - 局部不同

c# - 如何在不同的函数中使用 dispatcherTimer.Stop?

c# - 从控制台生成/打开 CSV - 文件格式错误

performance - 使用 'similar to' 在 PostgreSQL 中查询性能