Prestazioni Linq per la raccolta in memoria

Ho una lista: utenti della collezione che ha circa 100K + record di utenti (tutti gli oggetti utente completamente caricati dal database con campi come Bio, Nome, cognome ecc.). Questa raccolta viene recuperata all’avvio dell’applicazione dal database e viene mantenuta in memoria.

Quindi ho il codice come:

User cachedUser = users.FirstOrDefault(x => string.Equals(x.UserName, username, StringComparison.CurrentCultureIgnoreCase)); 

Che uso per recuperare utenti da questa collezione. Ma in qualche modo ho notato che questa operazione è incredibilmente lenta. Esiste un problema di prestazioni durante l’utilizzo di Linq per eseguire query nella raccolta di memoria di oggetti di grandi dimensioni? Dovrei invece chiamare il DB ogni volta che voglio ottenere un utente?

Se desideri ottimizzare il tempo di risposta e potresti creare un Dictionary e cercare l’utente all’interno di:

  Dictionary usersDictionary = new (StringComparer.CurrentCultureIgnoreCase); // After querying the users from the DB add them to the dictionary usersDictionary.Add(user.UserName, user); // Then when you need to retrieve a user User retrieveUser = null; usersDictionary.TryGetValue(username, out retrieveUser); 

Spero che sia d’aiuto !

Penso che potresti dover ripensare la tua architettura basandoti sulle informazioni che ci hai fornito. Approfitta del database e lascia che faccia la ricerca per te. Osservare, misurare e apportare modifiche di conseguenza. Potresti capire che hai ottimizzato prematuramente il tutto.

La tua query LINQ come qualsiasi altra tecnica di iterazione (loop, search in array) accederà a ogni singolo record fino a quando non viene trovato il record richiesto. Nel peggiore dei casi ciò significa confronti a 100k. Per rendere questo più veloce, hai le seguenti opzioni:

  1. usa una lista ordinata o un dizionario: una ricerca binaria è molto più veloce. Ordina i dati quando li recuperi dal database usando ORDER BY
  2. utilizzare un DataSet. È come un database In-Memory che offre una ricerca più rapida
  3. Lascia i dati nel database e imposta gli indici appropriati per un accesso più rapido

Suggerisco di utilizzare il database per i seguenti motivi:

  • È uno spreco di memoria per memorizzare record di 100k, che probabilmente non utilizzerai mai
  • Non appena cambi i tuoi dati, dovrai aggiornare la cache, che potrebbe essere piuttosto complessa
  • le applicazioni web sono multithreaded (ogni richiesta viene eseguita nella propria thread). Nel caso in cui cambi i tuoi dati, dovrai sincronizzarli con i blocchi.
  • un database può memorizzare nella cache dati chiamati frequentemente
  • devi scrivere meno codice
  • hai un’applicazione web stateless che si adatta meglio (web farm)
  • la tua applicazione probabilmente ha altri dati, non puoi memorizzare tutto in memoria

La differenza tra le prestazioni di ricerca che si notano è dovuta al fatto che il database utilizza l’indicizzazione per individuare la stringa nel database, ma nella memoria è sufficiente cercare tutti i record finché non si trova quello. Inoltre, il database mantiene un numero di hash per la stringa e cerca questo hash del numero molto più veloce e non confronta effettivamente la stringa.

Il Dictionary<> fa anche un indicizzazione, ma ha un ritardo nell’aggiungere dati, quando i dati iniziano a crescere perché quando si aggiungono alcuni dati, ogni volta si cerca dove collocarli nel punto indice corretto.

Anche il database memorizza nella cache i risultati, molti database nascondono anche l’indicizzazione e creano statistiche aggiuntive che aiutano a localizzare velocemente ciò che stai cercando.

È meglio lasciare che il database faccia la ricerca, eccetto se è ansible fare qualcosa di più veloce per casi personalizzati extra.