Saturday, August 02, 2008

LINQ - Cuestiones de performance - II

Bien, para terminar con esta serie de posts (2/2), partiremos de algo mencionado en la sección consideraciones del post anterior.
No es recomendable el uso de datasets. Entonces, continuemos con el trabajo!

La prueba -digamos, más- real es cuando se trabaje bajo un modelo con la siguiente combinación:

- Uso de Entidades (Clases mapeadas a las tablas de la base datos)
- Procedimientos Almacenados
- DataReaders
- Carga en Listas Genéricas de entidades

Luego de esto se revisarán los siguientes casos:
- Linq en C# - Procedure/DataReader/Lista Genérica en C#
- Linq usando Stored Procedure en C# - Procedure/DataReader/Lista Genérica en C#

Los ejemplos serán una continuación de los usados el post anterior.
Comencemos pues.

Tiempos de Respuesta:  Linq en C# - Procedure/DataReader/Lista Genérica en C# - Linq usando Stored Procedure en C#
Para continuar debemos considerar que se necesita construir un stored procedure, una clase y cargar una lista genérica por medio de un DataReader.
Parte del código utilizado es el siguiente:

up_ListarClientes

SpListaCs 

Para el caso de Linq usando Procedures el código es el siguiente:
SpLinq
En este caso, se utiliza el método ListarClientes, que es un reflejo del procedimiento usado líneas arriba, si requieren información sobre como realizar este mapeo, les recomiendo este post de ScottGu.

Con esto y verificando los tiempos de respuesta, se obtiene lo siguiente:

Usando Jet Brains para el Ejemplo Linq en C# (Del post anterior)
TiemposCS

Usando Jet Brains para el Ejemplo Stored Procedure/DataReader/Lista Genérica en C#
TiemposSpDrLgCs

Usando Jet Brains para el Ejemplo Linq usando Stored Procedures en C#
TiemposSpLinq

Como puede observarse, el caso propuesto obtiene 1,853 ms contra los 2,521 ms entregados por el modelo Linq usando C#.
Si, es cierto, utilizar Stored Procedures desde Linq toma 4,911 ms. Es incomparable, no?
Pasemos entonces a la revisión del uso de memoria.

Hablemos de memoria:  Linq en C# - Procedure/DataReader/Lista Genérica en C# - Linq usando Stored Procedure en C#
Pasemos a los resultados del CLR Profiler.

Usando CLR para ejemplo Linq (Del post anterior)
MemoriaLinq

Usando CLR para ejemplo Stored Procedure/DataReader/Lista Genérica en C#
MemoriaCSReader

Usando CLR para ejemplo Stored Procedure en Linq
MemoriaLinqSp

Luego de la respectiva inspección, puede observarse que el consumo de recursos con Linq es considerable con respecto al modelo Procedures/Reader/Listas.
Si hablamos del modelo Linq2Sql "tradicional" (usando expresiones de consulta), el uso de recursos es casi el doble.
Pero si cambiamos a la alternativa de aprovechar los Stored Procedures, el consumo se incrementa hasta casi el triple.
Esto ultimo si que es preocupante.

Comentarios y Consideraciones
- El caso propuesto fue usando Northwind,
- Debemos recordar que hay un grupo en codeplex que está buscando algo mas acorde a la realidad, indicando que no se ajusta a las necesidades de Linq (y adicionales).
- A pesar de ello, el modelo no tiene mucha ciencia en lo que respecta a lógica de negocio requerida.
- En resumen es un stored procedure que ejecuta un filtro sobre dos campos (seleccionados al azar por el desarrollador, es decir, yo).
- Sinceramente creía que el modelo que combina Linq y Stored Procedures tendría mejor performance.
- El código usado para la ejecución del procedure desde Linq puede optimizarse (noten que uso una variable tipo "var" cuando defino la variable datacontext)
- A pesar de ello, los tiempos de respuesta, no cambian mucho (dejo a su elección la verificación de este caso)
- El consumo de recursos me parece preocupante, pero lamenteblemente he notado que muchas veces esto pasa a segundo plano.
- Un ejemplo claro para mi, es el Windows Vista.
- A mi me gusta, pero cuando lo usaba desde mi PC de 1GB me sentía como en los viejos tiempos, pero no tenia intención de desinstalar el SO, menos regresar a Windows XP.
- Ahora tengo 3GB, sigo feliz con el Vista.
- Creo haberlo comentado al menos una vez, Linq me gusta mas como herramienta de consultas contra otros objetos, no como alternativa al SQL.
- A menos claro que se cambie el modelo de SQLServer (SQL 2012? como diría David)
- Alguna explicación a los tiempos de respuesta y consumo de memoria?
- Yo creo que los mapeos que utiliza Linq para realizar las ejecuciones contra la Base de Datos son de alguna manera, una evolución a lo que se tenia con el uso de los Typed DataSets, los recuerdan?
- Recuerdan entonces que habian "Duelos" (por decirlo asi), entre usarlos o no usarlos?
- Volviendo al ejemplo propuesto, la consulta usada retorna 3 registros.
- Es un ejemplo simple, lo sé.
- Pero eso no deja de hacerlo usar tantos recursos.
- Consideran que si usara mas de 100 registros, las respuestas cambiarán considerablemente?
- Lo dejo a su elección.

Antes de despedirme, solo me queda agradecer a David por la presión a escribir estos posts, sino fuera asi, todo esto hubiera quedado en las conversaciones del msn.
Pues claro, a Carlos Walzer, por sus posts reveladores (e inspiradores, claro está).

Saludos[at]Cama

No comments: