2012-12-18 18 views
5

Ho una tabella di 200.000 record dove sto ricevendo solo i primi 10 utilizzando .Take() ma ci vogliono circa 10 secondi per ottenere i dati.Linq alle entità è molto lento utilizzando il metodo .Take()

La mia domanda è: il metodo .Take() recupera tutti i dati dal database e filtra i primi 10 sul lato client?

Ecco il mio codice:

mylist = (from mytable in db.spdata().OrderByDescending(f => f.Weight) 
            group feed by mytable.id into g 
            select g.FirstOrDefault()).Take(10).ToList(); 

spdata() è un Importa funzione dalla stored procedure.

Grazie

+7

Se siete curiosi di quello che viene eseguito sul database si dovrebbe agganciare un profiler fino al tuo DB e controlla i log, questo è il modo migliore per scoprirlo. – Chris

+1

Se spdata() restituisce i 200.000 allora sì, lo farà sul lato client. –

+0

Oltre al metodo di Chris, è anche possibile provare Linqpad e passare alla vista SQL dopo aver scritto la query per visualizzare l'SQL generato o inserire un punto di interruzione (con questo metodo http://stackoverflow.com/questions/1412863/how -do-i-view-the-sql-generated-by-the-entity-framework) per vedere cosa viene generato mentre il programma viene eseguito. –

risposta

8

La stored procedure restituisce probabilmente molti dati al client che è molto lento. Non è possibile eseguire una ricerca remota su una stringa. Ciò sarebbe possibile utilizzando una vista o una funzione valutata a livello di tabella.

Non c'è modo di utilizzare una copia in una query. Puoi solo eseguirlo da solo.

L'intenzione era probabilmente quella di eseguire lo Take(10) sul server. Affinché funzioni, è necessario passare a una query in linea, a una vista oa un TVF.

6

Il metodo di estensione Take fa non recuperare tutti i risultati dal database. Non è così che funziona Take.

Tuttavia la chiamata db.spdata() probabilmente recupera tutte le righe.

1

Io non sono sicuro al 100%, ma mi ricordo che si ottiene un risultato IEnumerable quando si chiama un SP utilizzando EF DataContext ...

ci sono un paio di era quello di ottimizzare le prestazioni:

  • Passa i criteri di ricerca come parametri SP e fai il filtraggio nella stored procedure.

Oppure, se si dispone di una molto semplice query nella SP in cui non si sta dichiarando variabili e dove si sono appena unendo alcune tabelle poi:

  • Creare una vista indicizzata in cui specificare la query che si bisogno e chiamare il metodo Take su di esso.
    Cosa ti darà questo? Puoi mappare alla vista creata e EF restituirà un risultato IQueryable e non un IEnumerable. Questo ottimizzerà il comando sql e piuttosto la ricezione di tutti i dati e quindi prendendo i 10 elementi di cui hai bisogno, verrà creato un comando sql che recupera solo i 10 elementi.

Inoltre consiglio di vedere qual è la deferenza tra IEnumerable vs IQueryable.

0

Lo fa, perché si stanno ordinando i dati prima del raggruppamento, cosa che non è possibile fare in SQL.

Si dovrebbe usare un aggregato per ottenere il peso più alto di ciascun gruppo, quindi ordinare i pesi per ottenere i dieci più grande:

mylist = (
    from mytable in db.spdata() 
    group feed by mytable.id into g 
    select g.Max(f => f.Weight) 
).OrderByDescending(w => w).Take(10).ToList(); 
+0

sta dando un errore Errore "Una variabile locale chiamata 'g' non può essere dichiarata in questo ambito perché darebbe un significato diverso a 'g', che è già usato in un ambito 'genitore o corrente' per indicare qualcos'altro" –

+0

@AliIssa: Esatto, deve esserci una variabile diversa lì. L'ho cambiato. – Guffa

Problemi correlati