Mi è stato chiesto di produrre un report guidato da una query SQL piuttosto complessa su un database SQL Server. Dal momento che il sito della relazione è stata già utilizzando Entity Framework 4.1, ho pensato di tentare di scrivere la query utilizzando EF e LINQ:Esiste un modo per ottimizzare questa query LINQ alle entità?
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()
};
Questa query collima voti, ma solo da parte degli utenti che hanno presentato un certo numero di voti minimi richiesti.
Questo approccio è stato un disastro completo dal punto di vista delle prestazioni, quindi siamo passati a ADO.NET e la query è stata eseguita molto rapidamente. Ho guardato l'SQL generato da LINQ usando SQL Profiler, e sebbene sembrasse atroce come al solito, non ho visto alcun indizio su come ottimizzare l'istruzione LINQ per renderla più efficiente.
Ecco la versione TSQL diritta:
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
Quello che mi chiedo è: è questa query troppo complessa per EF e LINQ per gestire in modo efficiente o Ho perso un trucco?
Sto indovinando tutti i FirstOrDefaults stanno causando esso. Hai provato ad aggiungere un 'let response = r.First()' prima del groupby? O scambiando il Select e l'OrderBy? Mi piace questo http://stackoverflow.com/a/5013740/736079 – jessehouwing
Esiste una proprietà di navigazione come 'User.Responses'? –
@jessehouwing usando let la risposta aiuta in modo considerevole, sebbene la versione LINQ sia ancora molto più lenta di ADO.NET. Se inserisci questo come risposta, lo involo almeno. Sto avendo problemi con la strategia di Jon Skeet di scambiare selezione e ordine, principalmente non riesco a capire come ottenere il conto con questo costrutto. –