Ho una semplice entità e ne ho 100.000 nel mio database SQL Sever 2012:
public class Entity
{
public int Id { get; set; }
public string Field1 { get; set; }
public string Field2 { get; set; }
}
Voglio mostrarli in una griglia, perché 100.000 sono troppi per essere visualizzati su uno schermo (e non molto efficienti). La griglia dovrebbe consentire l'ordinamento e il filtraggio - ovviamente tutte e 3 di queste operazioni sono fatte al meglio sul server, e EF dovrebbe tradurle.
Quindi, consente di ottenere la seconda pagina di 500 ordinati per Field1:
var items = context.Entities.OrderBy(e => e.Field1).Skip(500).Take(500);
Quando viene eseguita questa query, sono necessari 12 secondi ! Così l'ho scavato e ho trovato che è tradotto come di seguito:
SELECT TOP (500) [Extent1].[Id] AS [Id],
[Extent1].[Field1] AS [Field1],
[Extent1].[Field2] AS [Field2]
FROM (SELECT [Extent1].[Id] AS [Id],
[Extent1].[Field1] AS [Field1],
[Extent1].[Field2] AS [Field2],
row_number() OVER (ORDER BY [Extent1].[Field1] ASC) AS [row_number]
FROM [dbo].[Costs] AS [Extent1]) AS [Extent1]
WHERE [Extent1].[row_number] > 500
ORDER BY [Extent1].[Field1] ASC
Sicuramente questo viene ordinato due volte? Non sono un esperto SQL, ma gli ordini di sub-query di Field1 e assegnano questo ordine a row_number. Quindi prendiamo la TOP 500 row_numbers su 500 per ottenere fino a 500 righe per la pagina 2. Non è necessario ordinare nuovamente i risultati per Field1.
Se ORDER BY [Extent1].[Field1] ASC
finale di ORDER BY [Extent1].[Field1] ASC
, i risultati della query sembrano essere gli stessi e il tempo di esecuzione scende a circa 150 millisecondi.
Quindi, ovviamente, 150 ms è preferibile a 12 secondi - c'è qualcosa che sto sbagliando? C'è qualcosa che posso fare per risolvere questo problema?
Aggiornare
Il piano di query è lo stesso per entrambi. L'unica differenza nel suggerimento per l'ordinamento è "Numero di righe effettivo" di 4.604 per la query 12s e 1.134 per la query 150 ms. Vorrei aggiungere che questo è generato da una lista fissa di 15 parole (per questo test) - cioè Campo1 contiene 1 di 15 valori, quindi ci sono essenzialmente 15 gruppi di 6.666 righe.
Ciò è dovuto a un bug / idiosincrasia in SQL Server quando vengono combinati gli stream TOP e Gather. Un indice lo risolverà , così come disabiliterà il parallelismo (globalmente, o per questo utente o per la query). L'indizio era che Gather Streams versato a tempdb che è una condizione estremamente rara. http://web.archive.org/web/20180220120719/http://sqlblog.com:80/blogs/paul_white/archive/2012/05/03/parallel-row-goals-gone-rogue.aspx Questo è 500 roba di livello.
Nota che non puoi escludere l'ordine finale ORDER BY
perché questo rende l'ordine dei risultati indefinito.
Penso che il tuo problema sia dovuto all'ordine su una colonna grande e non indicizzata .
Assicurati di eseguire l'indicizzazione per quella colonna.
In ogni caso, la clausola order by
sarebbe migliore con i valori non nvarchar