バックグラウンド
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 クエリはこれに対して機能しますが、非常に遅く、結果を返すのに 1 分近くかかります。
/// <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();
}
質問
パフォーマンスに影響を与えずに、この "Most Recent Month Reported" の結果セットを照会するにはどうすればよいですか? 過去数時間にわたって、最も時間がかかっているクエリの部分を分離しようとしましたが、それを見つけることができないようです. 確かに、複雑な LINQ クエリでパフォーマンスの問題を効果的にプロファイルする方法がわかりません。コメントを受け付けています。
最終的な問題は次のとおりです。この LINQ クエリに代わるもので、このような深刻なパフォーマンスの低下なしに同じ結果セットを生成するものはありますか?
前もって感謝します。