Странная проблема тайм-аута LINQ to SQL с использованием FirstOrDefault () - PullRequest
1 голос
/ 15 марта 2012

У меня есть следующий код, который истекает:

        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 с помощью SQL Server Profiler и взял выполненный SQL. Как и ожидалось, он содержит ТОП-1. Когда я запускаю точный SQL в SQL Management Studio, он сразу возвращается. Тем не менее, он продолжает время ожидания в коде. Удивительно, но если поменять его на следующее, это прекрасно работает:

        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 в первом сценарии непосредственно в SQL Server проблем не было.

Может кто-нибудь объяснить, что здесь происходит? В данном случае это был групповой запрос, который всегда возвращал одну строку независимо. Так что мне повезло, что я могу перечислить перед применением FirstOrDefault (). Но для возможной будущей ссылки, что, если этот запрос вернул тысячи строк, для которых я хотел только TOP 1.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

SQL с использованием .FirstOrDefault ():

SELECT TOP 1 Field1, Field2...
FROM
(
    SELECT SUM(Field) as Field1, ...
    FROM ...
) SUB

SQL с использованием .ToArray ():

SELECT SUM(Field) as Field1, ...
FROM ...

Выполнение любого из них непосредственно в SQL Mgt Studio привело к одинаковым результатам за то же время. Однако, когда LINQ выполняет первый, я получаю тайм-аут.

1 Ответ

0 голосов
/ 26 марта 2015

Это распространенная проблема при использовании linq to sql.Если вы думаете о sql, то когда вы делаете группу по группам, а затем по умолчанию, вы просите, чтобы sql агрегировал, а затем не агрегировал.Для sql трудно иметь дело с отдельными элементами в группе, поскольку он будет выполнять несколько запросов для достижения отдельных элементов.

Когда вы выполняете ToArray, вы фактически вытягиваете данные обратно в память, а группа фактически сохраняется в памяти с отдельными элементами, поэтому их достижение будет намного быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...