背景
我有一个通过 LINQ-to-Entities 称为视图的 SQL 数据集。其目的是在信用报告中提供未结余额 30 天、60 天等未结余额。
在 StackOverflow 上为您提供一个示例表很难在此处格式化,但这里是 SQL SELECT 语句,它应该让您了解原始数据结构:
SELECT TOP 1000 [TransactionId]
,[IndustrySector]
,[DataContributorId]
,[ExperienceMonth]
,[ExperienceMonthText]
,[Balance]
,[ARCurrent]
,[AR1to30PD]
,[AR31to60PD]
,[AR61to90PD]
,[Ar91PlusPD]
,[WeightedDTP]
FROM [BCC].[dbo].[vwTransactionExperienceDetail]
现在,当我通过 LINQ 调用此视图时,最终目标是构造一个对象,该对象将作为 JSON 返回给请求客户端。结果对象需要是分组的层次结构Industry
,然后是Contributors
(报告的数据),最后是个人Reports
。为此,以下 LINQ 查询可以正常工作并且速度非常快:
/// <summary>
/// Gets the 25 month experience detail report with summed parameters (balance, DTP, etc).
/// </summary>
/// <param name="id">The transaction id.</param>
/// <returns>List<ExperienceDetail></returns>
public static List<ExperienceDetail> Get25MonthExperienceDetail_Sum(int id)
{
var db = new BCCEntities();
return
db.vwTransactionExperienceDetails.Where(te => te.TransactionId == id)
.GroupBy(g => g.IndustrySector)
.Select(i => new ExperienceDetail
{
Industry = i.Key,
NumberOfContributors = i.GroupBy(c => c.DataContributorId).Count(),
Balance = i.Sum(s => s.Balance),
OneToThirty = i.Sum(s => s.ARCurrent),
ThirtyOneToSixty = i.Sum(s => s.AR1to30PD),
SixtyOneToNinety = i.Sum(s => s.AR31to60PD),
NinetyOneToOneTwenty = i.Sum(s => s.AR61to90PD),
OneTwentyOnePlus = i.Sum(s => s.Ar91PlusPD),
DTP = (i.Sum(s => s.Balance) != 0) ? i.Sum(s => s.WeightedDTP) / i.Sum(s => s.Balance) : i.Sum(s => s.WeightedDTP),
Contributions = i.GroupBy(dc => dc.DataContributorId).Select(c => new Contribution
{
Balance = c.Sum(s => s.Balance),
OneToThirty = c.Sum(s => s.ARCurrent),
ThirtyOneToSixty = c.Sum(s => s.AR1to30PD),
SixtyOneToNinety = c.Sum(s => s.AR31to60PD),
NinetyOneToOneTwenty = c.Sum(s => s.AR61to90PD),
OneTwentyOnePlus = c.Sum(s => s.Ar91PlusPD),
DTP = (c.Sum(s => s.Balance) != 0) ? c.Sum(s => s.WeightedDTP) / c.Sum(s => s.Balance) : c.Sum(s => s.WeightedDTP),
ContributorId = c.Key,
Reports = c.Select(r => new Report
{
DTP = (r.Balance != 0) ? r.WeightedDTP/r.Balance : r.WeightedDTP,
ReportDate = r.ExperienceMonth,
Balance = r.Balance,
OneToThirty = r.ARCurrent,
ThirtyOneToSixty = r.AR1to30PD,
SixtyOneToNinety = r.AR31to60PD,
NinetyOneToOneTwenty = r.AR61to90PD,
OneTwentyOnePlus = r.Ar91PlusPD,
ContributorId = r.DataContributorId,
Industry = i.Key
})
})
}).ToList();
}
问题
我需要创建一个提供相同数据的附加服务,但仅限于每个贡献者报告的最近一个月DataContributorId
( )。以下 LINQ 查询适用于此,但速度极慢 - 返回结果需要将近一分钟:
/// <summary>
/// Gets an experience detail report with summed parameters (balance, DTP, etc) for the most recent month.
/// </summary>
/// <param name="id">The transaction id.</param>
/// <returns>List<ExperienceDetail></returns>
public static List<ExperienceDetail> Get25MonthExperienceDetail_MostRecentMonth(int id)
{
var db = new BCCEntities();
db.CommandTimeout = 100000;
return
db.vwTransactionExperienceDetails.Where(te => te.TransactionId == id)
.OrderByDescending(o => o.ExperienceMonth)
.GroupBy(g => g.IndustrySector)
.Select(i => new ExperienceDetail
{
Industry = i.Key,
NumberOfContributors = i.GroupBy(c => c.DataContributorId).Count(),
Balance = i.GroupBy(dc => dc.DataContributorId).Sum(x => x.Select(z => z.Balance).FirstOrDefault()),
OneToThirty = i.Sum(s => s.ARCurrent),
ThirtyOneToSixty = i.Sum(s => s.AR1to30PD),
SixtyOneToNinety = i.Sum(s => s.AR31to60PD),
NinetyOneToOneTwenty = i.Sum(s => s.AR61to90PD),
OneTwentyOnePlus = i.Sum(s => s.Ar91PlusPD),
DTP = (i.Sum(s => s.Balance) != 0) ? i.Sum(s => s.WeightedDTP) / i.Sum(s => s.Balance) : i.Sum(s => s.WeightedDTP),
Contributions = i.GroupBy(dc => dc.DataContributorId).Select(c => new Contribution
{
Balance = c.Take(1).Sum(s => s.Balance),
OneToThirty = c.Take(1).Sum(s => s.ARCurrent),
ThirtyOneToSixty = c.Take(1).Sum(s => s.AR1to30PD),
SixtyOneToNinety = c.Take(1).Sum(s => s.AR31to60PD),
NinetyOneToOneTwenty = c.Take(1).Sum(s => s.AR61to90PD),
OneTwentyOnePlus = c.Take(1).Sum(s => s.Ar91PlusPD),
DTP = (c.Take(1).Sum(s => s.Balance) != 0) ? c.Take(1).Sum(s => s.WeightedDTP) / c.Take(1).Sum(s => s.Balance) : c.Take(1).Sum(s => s.WeightedDTP),
ContributorId = c.Key,
Reports = c.Select(r => new Report
{
DTP = (r.Balance != 0) ? r.WeightedDTP / r.Balance : r.WeightedDTP,
ReportDate = r.ExperienceMonth,
Balance = r.Balance,
OneToThirty = r.ARCurrent,
ThirtyOneToSixty = r.AR1to30PD,
SixtyOneToNinety = r.AR31to60PD,
NinetyOneToOneTwenty = r.AR61to90PD,
OneTwentyOnePlus = r.Ar91PlusPD,
ContributorId = r.DataContributorId,
Industry = i.Key
}).Take(1)
})
}).ToList();
}
问题
如何在不影响性能的情况下查询此“最近报告的月份”结果集?在过去的几个小时里,我尝试隔离查询中花费最多时间的部分,但我似乎无法发现它。诚然,我不知道如何有效地分析复杂 LINQ 查询的性能问题,并愿意发表评论。
最终的问题是:是否有替代此 LINQ 查询的替代方法,它会产生相同的结果集而不会造成如此严重的性能损失?
提前致谢。