繁体   English   中英

使用FirstOrDefault()怪异的LINQ to SQL超时问题

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM