У меня есть огромная проблема с временем выполнения запросов 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, я получаю хорошее время выполнения запроса при каждом прогоне, поэтому дизайн БД не должен быть проблемой, хотя он может быть не самым эффективным решение в любом случае.
Возможно, это не ответ для вас, просто мысль. Вы можете создать представление для своего отчета, а затем запросить представление, чтобы получить результаты. Это обеспечило бы, чтобы запрос выполнялся нормально в SQL каждый раз, из того, что вы говорите. –
Эй, спасибо за ваш комментарий! Не пытались создавать представления. Не могли бы вы указать мне правильное направление, чтобы начать с них? – veturi
Я отправил ответ, вы можете запросить подробности там. –