[英]Weird LINQ to SQL Timeout Issue using FirstOrDefault()
我有以下代碼超時:
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
ECWSDataContext dc = new ECWSDataContext();
IQueryable<Ticket> results = dc.Tickets;
Business.TicketStatistic statistic = results
.Select(r => new
{
GroupID = 1,
IsVoided = r.IsVoided ? 1 : 0,
IsWarning = r.TicketFilingTypeID == 5 ? 1 : 0,
TotalFelonies = r.TotalFelonies,
TotalMisdemeanors = r.TotalMisdemeanors,
TotalInfractions = r.TotalInfractions,
TotalOrdinances = r.TotalOrdinances,
TotalWarnings = r.TotalWarnings
})
.GroupBy(t => t.GroupID)
.Select(g => new Business.TicketStatistic()
{
TotalTickets = g.Count(),
TotalVoids = g.Sum(x => x.IsVoided),
TotalTicketWarnings = g.Sum(x => x.IsWarning),
TotalFelonies = g.Sum(x => x.TotalFelonies),
TotalMisdemeanors = g.Sum(x => x.TotalMisdemeanors),
TotalInfractions = g.Sum(x => x.TotalInfractions),
TotalOrdinances = g.Sum(x => x.TotalOrdinances),
TotalOffenseWarnings = g.Sum(x => x.TotalWarnings)
}).FirstOrDefault();
}
我使用SQL Server Profiler對SQL進行了概要分析,並獲取了已執行的SQL。 正如預期的那樣,它包含一個TOP1。當我在SQL Management Studio中運行確切的SQL時,它很快就會回來。 但是,它在代碼中繼續超時。 令人驚訝的是,將其更改為以下內容就可以了:
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
ECWSDataContext dc = new ECWSDataContext();
IQueryable<Ticket> results = dc.Tickets;
var stats = results
.Select(r => new
{
GroupID = 1,
IsVoided = r.IsVoided ? 1 : 0,
IsWarning = r.TicketFilingTypeID == 5 ? 1 : 0,
TotalFelonies = r.TotalFelonies,
TotalMisdemeanors = r.TotalMisdemeanors,
TotalInfractions = r.TotalInfractions,
TotalOrdinances = r.TotalOrdinances,
TotalWarnings = r.TotalWarnings
})
.GroupBy(t => t.GroupID)
.Select(g => new Business.TicketStatistic()
{
TotalTickets = g.Count(),
TotalVoids = g.Sum(x => x.IsVoided),
TotalTicketWarnings = g.Sum(x => x.IsWarning),
TotalFelonies = g.Sum(x => x.TotalFelonies),
TotalMisdemeanors = g.Sum(x => x.TotalMisdemeanors),
TotalInfractions = g.Sum(x => x.TotalInfractions),
TotalOrdinances = g.Sum(x => x.TotalOrdinances),
TotalOffenseWarnings = g.Sum(x => x.TotalWarnings)
}).ToArray();
Business.TicketStatistic statistic = stats.FirstOrDefault();
}
我知道現在在將FirstOrDefault()應用於當前內存中的集合之前,先枚舉結果。 但是,在第一種情況下直接在SQL Server中直接執行相同的SQL輸出沒有問題,這似乎很奇怪。
有人可以解釋這是怎么回事嗎? 在這種情況下,無論如何,它都是始終返回一行的組查詢。 因此,我很幸運能夠在應用FirstOrDefault()之前進行枚舉。 但是,為了將來提供參考,如果該查詢返回了我只希望返回TOP 1的數千行,該怎么辦?
附加信息
使用.FirstOrDefault()的SQL:
SELECT TOP 1 Field1, Field2...
FROM
(
SELECT SUM(Field) as Field1, ...
FROM ...
) SUB
使用.ToArray()的SQL:
SELECT SUM(Field) as Field1, ...
FROM ...
直接在SQL Mgt Studio中執行任一操作會在相同的時間內產生相同的結果。 但是,當LINQ執行第一個時,我超時了。
使用linq到sql時,這是一個常見問題。 如果您考慮使用sql,則在進行group by然后是firstordefault時,您是在要求sql進行聚合,然后再進行非聚合。 對於sql來說,很難通過組來處理單個元素,因為它將執行多個查詢以到達單個元素。
當您執行ToArray時,實際上是將數據拉回到內存中,而分組依據實際上是與各個元素一起存儲在內存中的,因此到達這些元素的速度會快得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.