.net - sintaxis - ¿Cuán escalable es LINQ?
ordenar en linq (10)
Conversaciones recientes con colegas han producido diferentes puntos de vista sobre este asunto. ¿Qué dicen ustedes, SO miembros?
Lo sé, incluso el concepto de escalabilidad se puede tomar de muchas maneras y contextos diferentes, pero eso fue parte de la discusión cuando surgió. Todos parecían tener una opinión diferente sobre lo que realmente significa la escalabilidad. Tengo curiosidad de ver las diferentes tomas aquí también. De hecho, publiqué una pregunta solo por ese concepto.
En mi opinión, LINQ pretende simplificar las cosas desde un punto de vista de desarrollo, no para abordar la escalabilidad.
De hecho, el uso de LINQ hace las cosas tan fáciles al esconder muchas complicaciones debajo de las coberturas, y podría llevar, cuando se usa irresponsablemente , a problemas de escalabilidad.
Abundan los ejemplos en otras respuestas, pero para mencionar las más importantes:
Si está consultando una colección de objetos, no puede ignorar su tamaño. Tal vez hacerlo en el modelo, con LINQ, sonaba bien cuando había unos pocos objetos para consultar ... pero a medida que el tamaño crece, se hace evidente que la consulta debería ocurrir en la base de datos, no en el modelo.
Si está autogenerando SQL con LINQ, hasta donde yo sé, no puede dar pistas sobre cómo compilar consultas en la base de datos, por ejemplo
WITH (NOLOCK)
. A medida que crecen los tamaños de su mesa, es imperativo poder abordar estos problemas.Similar a lo anterior, pero tal vez más general: cuando aborda problemas de escalabilidad sobre un DB, tiene que controlar lo que está haciendo el DB. Tener un lenguaje que se compila en SQL, que luego se compila de nuevo en un plan de ejecución, elimina el control de sus manos.
¿Qué sucede si tiene que cambiar su esquema de base de datos para hacerlo más escalable y su código está fuertemente ligado a él porque no tiene procedimientos almacenados?
Aunque parece simple, no puede cambiar el proveedor de LINQ sin mucho dolor: consultar SQL Server no es lo mismo que consultar un objeto o consultar XML. El LINQ es muy similar sin embargo. Espero que algunos de mis desarrolladores junior participen en un "LINQ spree" porque es más fácil que aprender cómo hacer cosas teniendo en cuenta la escalabilidad.
En conclusión, creo que es posible escribir código escalable con LINQ, pero solo utilizándolo con cuidado. No hay herramientas asesinas, solo código asesino.
Depende mucho del proveedor de LINQ que esté utilizando y de cómo lo esté utilizando. Es probable que LINQ no conozca la increíble velocidad de ejecución, sino que les brinde a los desarrolladores una productividad sustancialmente mejor.
De acuerdo con este enlace, incluso con algunos de los CTP, Linq to SQL ya era mejor que usar SQL directo en algunos casos.
Si le preocupa Speed y está utilizando LINQ para objetos, aquí hay un proyecto codeplex (creo) para un proveedor que puede ofrecerle mejoras de rendimiento de 1000x.
Esta pregunta es un poco como preguntar "¿Qué tan escalables son las colecciones?"
Vamos a hablar de LINQ a los objetos. En términos generales, en la medida en que la mayoría de las implementaciones de IEnumerable<T>
iteran sobre cada elemento en la colección subyacente, LINQ tiene un gran potencial para escalar mal. Cree una List<Foo>
que contenga diez millones de elementos y algo como esto:
var list = from Foo f in fooList
where f.Value = "Bar"
select f;
va a ser lento Pero eso realmente no es culpa de LINQ. Tú eres el que le dio una lista de diez millones de artículos.
Usted trata con esto de la misma manera en que lo haría si LINQ no existiera: compilando Diccionarios y SortedLists y elementos similares que lo ayuden a reducir el espacio de búsqueda.
LINQ puede mejorar la escalabilidad (bueno, hacer que la escalabilidad sea más fácil de conseguir) mediante la ejecución diferida de consultas. Puede reemplazar un método ingenuo que crea una lista, la filtra a una nueva lista, la filtra a una nueva lista, etc. con una serie de consultas LINQ:
var list1 = from Foo f in fooList where f.Value1 = "Bar" select f;
var list2 = from Foo f in list1 where f.Value2 = "Baz" select f;
var list3 = from Foo f in list2 where f.Value3 = "Bat" select f;
todos los cuales se ejecutan sobre un solo pase a través de la colección subyacente cuando (y si) se vuelve necesario iterar sobre la lista final. De nuevo, sin embargo, esto no es nada nuevo: si no tuviera LINQ, probablemente terminaría reemplazando su método ingenuo por uno que hiciera lo mismo. Pero LINQ lo hace mucho más fácil.
La escalabilidad y el rendimiento son dos cosas diferentes pero relacionadas. Si desea medir el rendimiento, necesita ver cuántos usuarios (por ejemplo) puede admitir con un solo cuadro. Cuando mide la escalabilidad, agrega otra casilla y ve si puede soportar el doble de la cantidad original. No es probable, y es posible que solo agregue el 75% a su potencia de procesamiento, la siguiente solo agrega el 50% de la unidad original, por lo que baja a cero bastante rápido. No importa cuántas casillas agregue a esa velocidad, tiene la suerte de duplicar el número de usuarios admitidos. Eso es escalabilidad.
La escala de su módulo Linq probablemente dependa más de la base de datos, cuán potente es la máquina, cuál es el diseño de la base de datos, cuál es el diseño de su aplicación.
A menudo se ven micro-puntos de referencia que se supone que revelan algo concluyente, pero nunca lo hacen porque son solo una vista clave de todo el problema.
Puedes sacar el buen viejo ejemplo 20/80 aquí. Probablemente sea un 20% sobre la herramienta y un 80% sobre todo tipo de elementos tangibles que componen su aplicación.
Su pregunta sobre la escalabilidad de alguna manera depende de para qué está utilizando LINQ. En las aplicaciones comerciales, no vas a encontrar una gran cantidad de comandos SQL que se ejecutan: son lentos y deben compilarse en el DBMS. Lo que verá en su lugar son muchas llamadas a procedimientos almacenados. Estos serán un poco más rápidos en LINQ.
Tenga en cuenta que LINQ to SQL y similares están basados en TOP de ADO.NET, no son una metodología completamente diferente ni nada por el estilo. Claro, LINQ to XML usará diferentes API bajo las cubiertas. Esto se parecerá mucho a un compilador: siempre hay algunas optimizaciones que los humanos pueden hacer que podrían ser más rápidas, pero en su mayor parte, estas API podrán generar código más rápido y menos problemático que el código que usted mismo escribe.
En términos de escalamiento, siempre puede poner LINQ detrás de un servicio web si desea distribuir sus datos un poco o puede usar la replicación del servidor SQL. No debería ser menos escalable que ADO.NET.
Supongo que la mejor manera de verificarlo es escribiendo puntos de referencia, pero en mi opinión LINQ tiene la posibilidad de optimizaciones que el código similar de escritura a mano no ofrece. No sé qué tan bien se aprovecha de esos todavía.
LINQ te permite expresar lo que quieres, no cómo generarlo. Una ventaja obvia es que LINQ se puede paralelizar automáticamente (ver PLINQ ).
Otra ventaja de LINQ es que es floja, por lo que puede realizar cálculos, sacando de la colección según sea necesario. Podría codificar manualmente un equivalente, pero puede ser mucho más fácil hacerlo bien en LINQ.
En las pruebas que hicimos, LINQ to objects (ForEach) fue aproximadamente 2 veces más lento que el ciclo foreach.
LINQ to SQL (base de datos MS SQL) es casi 10 veces más lento que la consulta directa utilizando el lector de datos, la mayoría de las veces crea SQL desde el árbol de expresiones (por lo tanto, estará vinculado a la CPU y la base de datos estará inactiva) Para evitar esto, debe usar consultas compiladas
Vea esto para más. La mayoría de la información en la publicación sigue siendo válida con .NET 3.5 SP1.
Si está buscando un ejemplo de la vida real, utiliza Linq en gran medida, consulte esta publicación / podcast .
Hay un precio para el almacenamiento en caché y la carga de objetos bajo demanda utilizando el marco Linq to SQL. Si un objeto puede cargar partes de sí mismo en demanda, es muy probable que haya una referencia al contexto de datos dentro de cada objeto. Dicho sea de paso, ese contexto de datos también almacena en caché todos los objetos que se le solicitan. Lo que significa que si mantiene uno de sus objetos (ya sea en un caché o simplemente porque lo usa más adelante), no solo está sosteniendo ese objeto, sino también cada objeto que el contexto de datos haya solicitado. Nunca obtendrán basura recolectada porque todavía se están haciendo referencia a ellos.
Esto no es un problema si todos sus objetivos tienen una corta vida útil, y la aplicación crea nuevos DataContexts cada vez que hace un nuevo trabajo. Pero puedo ver cómo podría crear problemas de escalabilidad, si alguien no estuviera consciente de la carga adicional que acompaña a cada objeto.
Linq es scalabile de muchas maneras.
Un aspecto es la implementación de la especificación detrás de linq, que permite interpretar que Expression se queda sin proceso, en un idioma diferente (Linq2Sql, Linq2Hibernate) o en un entorno informático distribuido, como un clúster map-reduce para ese asunto ( DryadLINQ )
Otro aspecto es la semántica que proporciona linq al lenguaje. Puede recorrer miles de millones de objetos sin llenar la colección en la memoria si su proveedor admite la carga diferida o puede paralelizar u optimizar la consulta (PLINQ o i4o).