背景
我有一个SQL数据集,通过LINQ-to-Entities被称为视图.其目的是在信用报告中提供未付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返回给请求客户端的对象.生成的对象需要按行业分组,然后是贡献者(报告的数据),最后是单个报告.为此,以下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查询是否有替代产生相同的结果集而没有如此严重的性能损失?
提前致谢.
最佳答案 假设数据集相当小,我只需要拉入所有月份,转到ToList(),然后过滤掉内存中最近一个月的数据.当查询变得复杂时,LINQ可以做一些非常奇怪的事情.