2010-07-13 16 views
13

Después de fairamountofresearch y algunos errors, modifiqué mi código para que cree un nuevo DataContext cada vez que se consulta la base de datos o se insertan datos. Y la base de datos se consulta con frecuencia: para cada una de las 250k transacciones que se procesan, se consulta la base de datos para obtener un ID de cliente, ID de departamento y categoría antes de insertar la transacción.¿Por qué la reutilización de un DataContext tendría un impacto negativo en el rendimiento?

Así que ahora estoy tratando de optimizar el código, ya que solo estaba procesando alrededor de 15 transacciones por segundo. Eliminé algunas consultas extrañas y agregué algunos índices y lo obtuve hasta 30/seg. Luego pensé que, aunque todo el mundo dice que un DataContext es liviano, tiene que costar algo para crear uno nuevo 4 veces por transacción, así que intenté reutilizar el DataContext. Descubrí, para mi sorpresa, que al reutilizar el contexto, el rendimiento se degradaba a 10 transacciones por segundo.

¿Por qué sería este el caso? ¿Es porque el DataContext guarda en caché las entidades en la memoria y primero busca a través de su lista en memoria antes de consultar la base de datos? Entonces, si, por ejemplo, busco la identificación del cliente (clave principal) para el cliente con el nombre 'MCS' y la columna del nombre del cliente tiene un índice agrupado para que la consulta de la base de datos sea rápida, la memoria interna la búsqueda será más lenta?

¿Y es cierto que la creación/eliminación de tantas conexiones de base de datos podría ralentizar las cosas, o se trata simplemente de otra optimización prematura? Y si es cierto, ¿hay alguna manera de reutilizar un DataContext pero hacer que realice una consulta de base de datos real para cada consulta de linq a sql?

Respuesta

12

Aquí es la razón por la reutilización de un DataContext no es una buena práctica, desde el MSDN DataContext documentation:

El DataContext es la fuente de todas las entidades asignadas través de una conexión de base de datos . Realiza un seguimiento de los cambios que realizados en todas las entidades recuperadas y mantiene una "caché de identidad" que garantiza que las entidades recuperados más de una vez están representados por utilizando la misma instancia de objeto.

En general, es una instancia de DataContext diseñado para una duración de una "unidad de trabajo", sin embargo su aplicación define ese término. Un DataContext es liviano y no es costoso para crear. Una aplicación LINQ to SQL típica crea instancias de DataContext en el ámbito del método o como un miembro de clases efímeras que representan un conjunto lógico de operaciones de bases de datos relacionadas .

Si está reutilizando un DataContext para un gran número de consultas, el rendimiento se degradará por un par de razones posibles:

  1. Si de DataContext en memoria caché de identidad se hace tan grande que tiene que comenzar a escribir en el archivo de paginación, entonces su desempeño estará ligado a la velocidad del cabezal de lectura del disco duro y efectivamente no habrá una razón para usar un caché.

  2. Cuantos más objetos de identidad hay en la memoria, más tarda cada operación de guardado.

Esencialmente lo que estás haciendo es violar el principio UoW para la clase DataContext.

Abrir conexiones de base de datos tiene algunos gastos generales asociados, pero mantener una conexión abierta durante un largo período de tiempo (que a menudo también significa bloquear una tabla) es menos preferible que abrirlas y cerrarlas rápidamente.

Otro vínculo que puede o no puede ayudar a partir de MSDN:

How to: Reuse a Connection Between an ADO.NET Command and a DataContext (LINQ to SQL)

1

Incluso con un índice agrupado, la búsqueda en memoria siempre será más rápida que una consulta de base de datos, excepto en casos extremos, como un 386 frente a un Cray, incluso si se tienen en cuenta los retrasos relacionados con la red.

Supongo que la degradación tiene que ver con el manejo de DataContext de las entidades que rastrea: la reutilización de un contexto aumentará continuamente el número de entidades rastreadas, y la llamada a SaveChanges puede requerir más tiempo.

De nuevo, eso es una suposición, pero es donde empezaría a buscar.

1

Usted tendría para perfilar todo de extremo a extremo y ver donde realmente se gasta su tiempo.

Un índice agrupado no es necesariamente el más rápido si una fila es ancha. El más rápido probablemente sea un índice no agrupado que cubra, pero eso es realmente irrelevante.

Espero que para obtener un mayor rendimiento, es probable que tenga que descartar algo del marco, si realmente no está utilizando las capacidades. Si está utilizando las capacidades, bueno, eso es lo que está pagando ...

1

No exactamente aquí, pero ha considerado algún tipo de caché a nivel de aplicación para buscar el ID del cliente, ID del departamento, y ¿categoría? No está claro por su publicación cuántas de estas entidades existen en su sistema, o qué implica consultarlas para obtenerlas.

Sin embargo, como ejemplo, si tiene un millón de categorías en su sistema y necesita buscar su Id por nombre de categoría, mantener un nombre/diccionario en la memoria para la búsqueda en todo momento le ahorrará un viaje a la base de datos para la transacción que procesa. Esto podría mejorar de forma masiva el rendimiento (esto supone algunas cosas, como que las nuevas guarderías no se agregan regularmente). Como regla general, los viajes redondos a la base de datos son costosos en comparación con las operaciones en memoria.

Cuestiones relacionadas