Zostałem poproszony o wygenerowanie raportu, który jest sterowany przez dość złożone zapytanie SQL przeciwko bazie danych SQL Server. Ponieważ strona raportu została już używając Entity Framework 4.1, pomyślałem, że spróbuję napisać kwerendę za pomocą EF i LINQ:Czy istnieje sposób na optymalizację tego zapytania LINQ do Entities?
var q = from r in ctx.Responses
.Where(x => ctx.Responses.Where(u => u.UserId == x.UserId).Count() >= VALID_RESPONSES)
.GroupBy(x => new { x.User.AwardCity, x.Category.Label, x.ResponseText })
orderby r.FirstOrDefault().User.AwardCity, r.FirstOrDefault().Category.Label, r.Count() descending
select new
{
City = r.FirstOrDefault().User.AwardCity,
Category = r.FirstOrDefault().Category.Label,
Response = r.FirstOrDefault().ResponseText,
Votes = r.Count()
};
To zapytanie pokrywa się głosy, ale tylko od użytkowników, którzy dostarczyli pewna liczba wymagane minimum głosów.
To podejście było całkowitą katastrofą z punktu widzenia wydajności, więc przełączyliśmy się na ADO.NET i zapytanie zostało wykonane bardzo szybko. Spojrzałem na wygenerowany przez LINQ SQL przy użyciu programu SQL Profiler i chociaż wyglądał on okropnie jak zwykle, nie widziałem żadnych wskazówek, jak zoptymalizować instrukcję LINQ, aby była bardziej wydajna.
Oto wersja prosta TSQL:
WITH ValidUsers(UserId)
AS
(
SELECT UserId
FROM Responses
GROUP BY UserId
HAVING COUNT(*) >= 103
)
SELECT d.AwardCity
, c.Label
, r.ResponseText
, COUNT(*) AS Votes
FROM ValidUsers u
JOIN Responses r ON r.UserId = u.UserId
JOIN Categories c ON r.CategoryId = c.CategoryId
JOIN Demographics d ON r.UserId = d.Id
GROUP BY d.AwardCity, c.Label, r.ResponseText
ORDER BY d.AwardCity, s.SectionName, COUNT(*) DESC
Co Zastanawiam się: czy ta kwerenda po prostu zbyt skomplikowane dla EF i LINQ aby skutecznie obsłużyć lub zostały pominięte trick?
Zgaduję, że przyczyną są wszystkie błędy FirstOrDefaults. Czy próbowałeś dodać 'let response = r.First()' przed groupby? Lub zamiana Select i OrderBy? Podoba mi się ten http://stackoverflow.com/a/5013740/736079 – jessehouwing
Czy istnieje właściwość nawigacji, taka jak 'User.Responses'? –
@jessehouwing za pomocą odpowiedzi let pomaga znacznie, chociaż wersja LINQ jest nadal znacznie wolniejsza niż ADO.NET. Jeśli wpiszesz to jako odpowiedź, to przynajmniej ją przegłosuję. Mam problem ze strategią zamiany Jona Skeeta i kolejności, głównie nie mogę wymyślić, jak uzyskać liczenie z tym konstruktem. –