[英]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.