2

У меня есть огромная проблема с временем выполнения запросов Sql Server, которое я отлаживал в течение длительного времени без успеха.LINQ для сущностей медленного запроса

В основном я создаю отчет, в котором статистика «Порядок» сгруппирована по заказу и показана пользователю. Проблема в том, что большую часть времени выполнение запроса достаточно быстро, но иногда оно резко падает и вызывает таймауты на сервере.

Что я получил от этого, так это то, что случайное невысокое качество запросов, по-видимому, вызвано параметром sniffing в SQL Server. Мои отношения имеют очень смешанное количество связанных строк; у некоторых отношений может быть 10 000 строк для одной родительской строки, но в следующей строке может быть только одна связанная строка. Я думаю, что это приводит к тому, что оптимизатор запросов в некоторых случаях полностью игнорирует индексы и выдает очень низкую производительность.

В принципе, я понятия не имею, как подойти с исправлением этой проблемы. Я либо должен как-то оптимизировать мой запрос, либо придумать какой-то способ заставить оптимизатор запросов использовать индексы каждый раз. К сожалению, хранимые процедуры не являются вариантом этого проекта.

То, что я пробовал, состоит в том, чтобы создавать независимые запросы для каждого «заказа», но поскольку в системе более 1000 заказов, что вызывает массовую медлительность и действительно не является вариантом. Самое близкое, что я получил, чтобы запустить его в разумное время выполнения, - это запрос, который, по-видимому, страдает от проблемы с параметризацией.

result = (from ord in db.Orders 
    join comm in db.Comments.Where(i => 
    i.UserId == userId && 
    i.Created >= startDate && 
    i.Created < endDate && 
    i.UserGroupId == channelId && 
    i.Campaign.CampaignCountryId == countryId && 
    (i.CommentStatus.Name == CommentStatus.Approved || i.CommentStatus.Name == CommentStatus.Pending)) 
    on ord.OrderId equals comm.OrderId into Comments 

    join motif in db.Motifs.Where(i => 
    i.UserId == userId && 
    i.Created > startDate && 
    i.Created < endDate && 
    i.UserGroupId == channelId && i.Campaign.CampaignCountryId == countryId) 
    on ord.OrderId equals motif.OrderId into Motifs 

    where ord.EndDate > startDate 

    select new ReportRow() 
    { 
     OrderName = ord.Name, 
     OrderId = ord.OrderId, 
     ChannelId = channelId, 

     Comments = Comments.Count(c => c.CommentStatus.Name == CommentStatus.Approved), 
     PendingComments = Comments.Count(c => c.CommentStatu.Name == CommentStatus.Pending), 

     Motifs = Motifs.Count(), 
     UniqueMotifs = Motifs.GroupBy(c => c.Uin).Count(), 

     ApprovedValue = ((decimal?)Motifs.GroupBy(c => c.Uin).Select(c => c.FirstOrDefault()).Sum(c => c.Value) ?? 0) + ((decimal?)Comments.Where(c => c.Commentstatu.Name == Commentstatus.Approved).Sum(c => c.Value) ?? 0), 

     PendingValue = ((decimal?)Comments.Where(c => c.Commentstatu.Name == Commentstatus.Pending).Sum(c => c.Value) ?? 0) 
    }).ToList(); 

return result; 

Любая помощь и идеи о том, как сделать свою отчетность работать достаточно быстро каждый раз, было бы весьма признателен - независимо от того, если это запрос оптимизации себя или некоторые удивительные идеи для представления в SQL в целом.

Я использую Azure SQL, если это имеет значение.

Также обратите внимание, что когда я запускаю сгенерированный запрос из LINQ выше в SSMS, я получаю хорошее время выполнения запроса при каждом прогоне, поэтому дизайн БД не должен быть проблемой, хотя он может быть не самым эффективным решение в любом случае.

+0

Возможно, это не ответ для вас, просто мысль. Вы можете создать представление для своего отчета, а затем запросить представление, чтобы получить результаты. Это обеспечило бы, чтобы запрос выполнялся нормально в SQL каждый раз, из того, что вы говорите. –

+0

Эй, спасибо за ваш комментарий! Не пытались создавать представления. Не могли бы вы указать мне правильное направление, чтобы начать с них? – veturi

+0

Я отправил ответ, вы можете запросить подробности там. –

ответ

0

Возможно, это не ответ для вас, просто мысль. Вы можете создать представление для своего отчета, а затем запросить представление, чтобы получить результаты. Это обеспечило бы, чтобы запрос выполнялся нормально в SQL каждый раз, из того, что вы говорите.

Вы используете их аналогично таблицам и можете делать любые запросы на них.

Отметьте это сообщение для some tips on consuming views in EF.

+0

Спасибо за ваш ответ.К сожалению, представление не решает мою проблему, так как мне нужно сделать запрос на основе некоторых переменных - вы можете увидеть их в моем исходном коде SQL LINQ. Также, как и в случае хранимых процедур, представления в этом проекте не являются приемлемым решением. – veturi

Смежные вопросы