2012-06-20 20 views
6

Tengo una lista: usuarios de la colección que tienen alrededor de 100K + registros de usuarios (todos los objetos de usuario completamente cargados de la base de datos con campos como Bio, Nombre, Apellido, etc.). Esta colección se obtiene al iniciar la aplicación desde la base de datos y se guarda en la memoria.Rendimiento de Linq para la colección en memoria

entonces he código como:

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

que utilizo a buscar a los usuarios de esta colección. Pero de alguna manera noté que esta operación es increíblemente lenta. ¿Hay algún problema de rendimiento al usar Linq para consultar en la colección de memoria de objetos grandes? ¿Debería llamar al DB cada vez que quiero obtener un usuario?

+7

Usted entiende que 'FirstOrDefault' es O (n), ¿verdad? Si tiene una colección muy grande, revisar cada elemento uno por uno llevará algo de tiempo. (y los dbs generalmente están indexados). Hay una variedad de formas de acelerar esto, una de las cuales es simplemente lanzarlo a un diccionario. ¿Hay alguna razón por la que no estás haciendo eso? –

+0

Quiero almacenar en caché todos los usuarios pensando que sería mejor por motivos de rendimiento, ya que se llama al método GetUser() en casi todas las páginas de mi aplicación. Si uso un diccionario, ¿será mucho más rápido? Es el diccionario O (1)? ¿O necesito ordenar primero mi dictionaory? –

+0

¿Solo necesita almacenar en caché al usuario actual? Solo puede usar el objeto incorporado 'Session' o' Cache' para eso. –

Respuesta

3

Si desea optimizar su tiempo de respuesta y se podría crear una Dictionary<T,U> y la búsqueda del usuario dentro:

Dictionary<string, User> usersDictionary = new <Dictionary<string, User>(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); 

Espero que ayude!

+0

Probablemente se refiera a 'new Dictionary (StringComparer.CurrentCultureIgnoreCase)' ya que la pregunta quiere insesitivity de caso – adrianm

+0

Sí, buen punto, gracias, actualizaré mi respuesta. –

+1

No creo que sea una buena idea cargar todos los usuarios en un diccionario. Eso requiere mucho tiempo y memoria.Además, debe sincronizar el acceso en caso de que también modifique los datos. – slfan

3

Su consulta LINQ como cualquier otra técnica de iteración (bucle, búsqueda en matriz) accederá a cada registro hasta que se encuentre el registro solicitado. En el peor de los casos, eso significa 100k comparaciones. Para hacerlo más rápido, tiene las siguientes opciones:

  1. utilizan una lista ordenada o un diccionario: una búsqueda binaria es mucho más rápida. Ordene los datos cuando los extraiga de la base de datos usando ORDER BY
  2. use un DataSet. Es como una base de datos en memoria que proporciona más rápido buscar
  3. dejar los datos en la base de datos y establecer los índices adecuados para un acceso más rápido

Es mejor utilizar la base de datos debido a las siguientes razones:

  • que es una pérdida de memoria para almacenar los registros de 100k, que es probable que nunca se utiliza
  • tan pronto como cambia sus datos, tendrá que refrescar la memoria caché, lo que podría ser bastante complejos
  • applicati web ons son multiproceso (cada solicitud se ejecuta en su propio hilo). En caso de que modifiques tus datos, deberás sincronizarlos con los bloqueos.
  • una base de datos puede almacenar en caché con frecuencia llamados datos
  • usted tiene que escribir menos código
  • usted tiene una aplicación web sin estado que escala mejor (granjas web)
  • su aplicación probablemente contiene otros datos, no se puede almacenar todo en memoria
+0

mi problema es que con tantos registros, incluso el acceso a la base de datos es lento. Así que pensé por qué no almacenar en caché todos los usuarios en la memoria ya que estoy usando eventos para administrar los objetos en caché cuando un usuario actualiza su perfil. ¿No podemos indexar esto en memoria caché de alguna manera? –

+3

¿Qué tipo de base de datos usas? 100k registros no es mucho, cuando se establece un índice en las filas que está buscando. Nunca guardaría tantos registros en la memoria dentro de una aplicación web. – slfan

+0

100K en nuestro DB pronto puede alcanzar 1M. El punto es que no importa qué RAM siempre será más rápido que los archivos de datos físicos. Entonces, ¿por qué no tener una búsqueda algorítmica de alto rendimiento en el código que utiliza una colección basada en RAM en lugar de confiar en DB? –

8

Creo que es posible que necesite volver a pensar su arquitectura en función de la información que nos ha proporcionado. Aproveche la base de datos y deje que la búsqueda funcione para usted. Observe, mida y realice los cambios en consecuencia después de eso. Puede darse cuenta de que optimizó prematuramente todo el asunto.

0

Lo diferente en el rendimiento de búsqueda que observa es porque la base de datos usa indexación para localizar la cadena en la base de datos, pero en la memoria puede buscar todos los registros hasta encontrar la. Además, la base de datos mantiene un número hash para la cadena y busca este hash numérico que es mucho más rápido y no hace comparaciones de cadenas en realidad.

El Dictionary<> también hace una indexación, pero tiene un retraso para agregar datos, cuando los datos comienzan a crecer porque cuando agrega algunos datos, cada vez es buscar dónde colocarlos en el punto de índice correcto.

También la base de datos almacena en caché los resultados, la caché de la base de datos también indexa y crea estadísticas adicionales que ayudan a localizar rápidamente lo que está buscando.

Es mejor dejar que la base de datos realice la búsqueda, excepto si puede hacer algo más rápido para casos personalizados adicionales.

Cuestiones relacionadas