LINQ TO SQL Performance

linq

 

 

LINQ o Language integrated query es un lenguaje de consultas integrado al lenguaje que fue introducido en las nuevas versiones de Visual Studio 2008, LINQ nos permite una sintaxis estándar para consultar diferentes fuentes de datos, sea SQL, XML u objetos en memoria.

Antes del framework 3.5, los desarrolladores típicamente usábamos ADO para consultar alguna que otra base de datos relacional, es decir si queríamos conectarnos y consultar alguna tabla usábamos las librerías de ADO específicamente System.Data.SqlClient. Si queríamos traer datos de la manera más rápida posible, entonces usábamos DataReaders, pero la responsabilidad del mantenimiento de la Data estaba a cargo del Desarrollador, y si el performance no era una de nuestras prioridades entonces optábamos por usar Datasets.

Luego de una conversación con mi amigo Dany Paredes, discutíamos acerca del Performance de LINQ TO SQL, para mi entender desarrollar con LINQ TO SQL es bastante rápido el desarrollo y todo eso, pero que ¿tal el performance?, decidí hacer las pruebas por mí mismo.

Escribí una Aplicación de Consola, para probar que tal el performance de LINQ TO SQL, ADO Datasets y ADO Datareader. La aplicación contiene 3 métodos los cuales cada uno de ellos consultan la tabla Customer de la base de datos northwind que contiene 91 registros 10,000 veces. En el caso para popular el Datareader cree una clase llamada clCustomer.

 

using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Configuration;
using System.Linq;



namespace LinqToSqlTest
{
    public class Program
    {
        public static string myconnectionstring = @"Data Source=.;Initial Catalog=northwind;User Id=sa;Password=sa;";

        static void Main(string[] args)
        {
            DateTime start;
            DateTime endTime;

            start = DateTime.Now;
            GetDataFromDatasets();
            endTime = DateTime.Now;
            Tiempo(start, endTime, "Usando Datasets");

            start = DateTime.Now;
            GetDataFromLinqToSQL();
            endTime = DateTime.Now;
            Tiempo(start, endTime, "Usando LINQ TO SQL");


            start = DateTime.Now;
            GetDataFromDataReaders();
            endTime = DateTime.Now;
            Tiempo(start, endTime, "Usando DataReaders");

            System.Console.ReadLine();
        }

        /// <summary>
        /// Traer los datos desde LINQ TO SQL
        /// </summary>
        private static void GetDataFromLinqToSQL()
        {
            LinqToSqlTestDataContext con = new LinqToSqlTestDataContext();
            var query = con.Customers;

            for (int i = 0; i < 10000; i++)
            {
                query.ToList();
            }
        }

        /// <summary>
        /// Metodo para Traer los datos en un reader
        /// </summary>
        private static void GetDataFromDataReaders()
        {
            SqlConnection con = new SqlConnection(myconnectionstring);
            string query = "select [CustomerID], [CompanyName], [ContactName], [ContactTitle], " +
            "[Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax]  from [dbo].[Customers]";
            SqlCommand command = new SqlCommand(query, con);
            con.Open();
            clCustomer sp = new clCustomer();
            for (int i = 0; i < 10000; i++)
            {
                SqlDataReader rdr = command.ExecuteReader();
                while (rdr.Read())
                {
                    sp.CustomerID = rdr["CustomerID"].ToString();
                    sp.CompanyName = rdr["CompanyName"].ToString();
                    sp.ContactName = rdr["ContactName"].ToString();
                    sp.ContactTitle = rdr["ContactTitle"].ToString();
                    sp.Address = rdr["Address"].ToString();
                    sp.City = rdr["City"].ToString();
                    sp.Region = rdr["Region"].ToString();
                    sp.PostalCode = rdr["PostalCode"].ToString();
                    sp.Country = rdr["Country"].ToString();
                    sp.Phone = rdr["Phone"].ToString();
                    sp.Fax = rdr["Fax"].ToString();

                }
                rdr.Close();
            }
        }

        /// <summary>
        /// Metodo para traer los resultados en un Dataset
        /// </summary>
        private static void GetDataFromDatasets()
        {
            SqlConnection con = new SqlConnection(myconnectionstring);
            string query = "select [CustomerID], [CompanyName], [ContactName], [ContactTitle], " +
            "[Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax]  from [dbo].[Customers]";
            SqlCommand command = new SqlCommand(query, con);
            SqlDataAdapter da = new SqlDataAdapter(command);
            DataSet ds = new DataSet();
            for (int i = 0; i < 10000; i++)
            {
                da.Fill(ds);
            }
        }

        private static void Tiempo(DateTime dt1, DateTime dt2, string message)
        {
            string time = ((dt2.Ticks - dt1.Ticks) / 10000000.0).ToString();
            System.Console.WriteLine(message + ": " + time + " Segundos");
        }
    }

    public class clCustomer
    {
        public string CustomerID { get; set; }
        public string CompanyName { get; set; }
        public string ContactName { get; set; }
        public string ContactTitle { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Region { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public string Phone { get; set; }
        public string Fax { get; set; }

    }
}

¿Cuáles fueron los resultados?

linqtosqlScreen

  • Datasets (29.313 segundos)
  • LINQ TO SQL (18.629 segundos)
  • DataReaders (18.037 segundos)

Así que tenemos que LINQ TO SQL es mas rápido que un Dataset y ligeramente más lento que un DataReader.

Si quieres puedes probarlo tu mismo copiando el código y creando un Linq To Sql Class llamado northwind.dbml. Solamente es necesario la tabla Customers.

Espero que les sea de utilidad.

10 comentarios en “LINQ TO SQL Performance”

  1. creo que tu ejemplo no se ajusta 100% a la realidad… ya que lo que muestras… en el mundo real no se usaria de ese modo….

    los ejemplos de este tipo no demuestran lo que en la realidad pasaria …., aunque si da una perspectiva de la velocidad …. no contempla todos los factores. te has puesto a pensar una app real.. que use linq cuantas veces aria llamadas a la db.. y eso como afectaria a la aplicacion…. no necesitan ser 10 000 llamadas en un bucle ( donde nadase hace entre llamada y llamda ) para hacer una aplicacion mas lenta.

    personalmente a mi parecer LINQ es bonito y facil de usar… pero en cuestion de performance… creo que no es su “lado bonito”

    esperemos que quiza en la V 3.0 de Linq las cosas mejoren 🙂

    Salu2

    Ddaz

  2. Saludos David, gracias por comentar, logicamente he hecho una prueba de una llamada con los distintas formas comunes que usamos los desarrolladores para conectarnos a la base de datos, es bien sabido que los Datareaders son bastante rapidos y todo eso, pero usar Datasets que es la forma mas comun de conexion no es la mas considerable, te puedo comentar que he trabajado con proyectos de mucha carga hechos en Linq To SQL y funcionan a la maravilla, pero bueno todo es cuestion de gustos. Saludos y se me cuida.

  3. Hola :

    bueno no se … parece que entendiste que te recomendaba que uses Dataset… si fue asi… pues … no era mi intencion esa… yo iba por otro punto….

    por ejemplo alli haces llamadas puras .. sin que nada lo interfiera .. si bien ayudan de estadistica… no es lo que pasa en una app real…
    en una app real tu controlas cuantas llamadas y que llamadas se hacen…( logicamente en linq puedes tbm controlar eso… pero cuantos lo hacen???…. es mucho mas codigo … ) en linq tu codificas de unba forma ” facil” … pero te has puesto a pensar cuantas llamadas hay hacia la db… bueno hay otros puntos que ya puso jersson en su post, el cual creo ya leiste. http://geeks.ms/blogs/jersson/archive/2008/07/29/linq-cuestiones-de-performance.aspx .

    como dijiste es cuestion de gustos.., linq de que funciona funciona … pero como nada es gratis en la vida el costo que tiene linq quiza para unos sea demasiado caro.

    pdta me pasaron este otro post .. checalo sobre optimizacion de linq : http://odetocode.com/Blogs/scott/archive/2008/07/14/12192.aspx
    Salu2

    Ddaz

  4. Gracias por el link, ciertamente el problema de linq son las llamadas que hacen, creo que no esta nada mal linq para estar primera vez entre la vida de los seres humanos, pero bueno, creo que en si, Linq si podria usarse con una DataAccess Layer que ya tenga uno implementada, depurada y que este funcionando, es decir estoy hablando de Linq To Object, y porque no, podriamos hacer nuestro propio provider.

    Un saludo y se me cuida.

  5. Hola de nuevo:

    alli ya me comentas de otro modo de linq, no del Linq2Sql, algo que a mi parecer esta pasando ( y tbm al parecer de varios con los que platique) es que esto es casi casi como volver a los Dataset… si a esos con los cuales en el 2002 / 2003 empezo la promocion de .net y ya luego se tuvo que enseniar que eso no era lo ” mejor” .. y en si que ni se recomendaba su uso… pero como ya el internet esta sobresaturado de info de conexiones a datos con datasets… hay muchas personas que empiezan y comenzaran usando datasets por que pensaran que es lo mas correcto ( debiendo usar por ejemplo listas genericas.) .
    Igual y en la version 3.0 de linq o la 4.0 de Entity framework esto este corregido… ( en la madrugada con jersson nos alucinabamos unas soluciones bien fumadas… jeje ) ,… pero se volvera a repetir el ciclo… muchas personas “por comodidad”, desinformacion y/o flojera seguiran usando el metodo incorrecto…. y esto se vuelve un circulo vicioso… asi como los paradigmas … que puso jersson en un post. seria bueno que veas esto: http://blogs.zdnet.com/microsoft/?p=1457

    Salu2

    Ddaz

  6. Hola

    En realidad el tema del uso de DataSets ha sido bien “bapuleado” y con razón en cuando a lo que el desempeño de la aplicación se refiere, pero por otro lado creo que tienen y han tenido su mérito en cuanto a la velocidad de desarrollo y simplicidad de uso, He visto que las comparaciones que haces no tomaste en cuenta a los tableAdapters, los ignoraste a estos por que internamente usan dataset ?

    Que opinas de los TableAdapters? son muy “simpaticos” en cuanto a su uso, super amigable su generación y entiendo que su desempeño en cuanto a la consultas de lectura es bastante bueno

    salu2
    Sergio

  7. Hola esteban, no se si me recuerdas/conoces yo estudie en ENAO, ssoy amigo de Jonathan(el manso), nada pasaba aver tu blog porque veo que me sigues en twitter, pura coincidencia ehh!!

    Nada, un saludo men!! ah si y esta muy interesante tu blog

  8. Amigos estoy seguro que LINQ es bueno porfin se deja de lado lo desgastante de memoria al usar los dataset fue el error mas grande de microsoft pues esos tipos de datos solo sirben en el mundo de microsotf es necesario mantener los lenguajes como son si es POO debes manejar objetos y LINQ te da esa opcion y la coomparacion no es tan justa pues si se analiza el tiempo de LINQ se ve algo mas lento pero es porq al poner eso datos en memoria los cargo como objetos ya tienes soporte para acceso a esos datos con su definicion adecuado osea si es ID int o si los NOMbres son string ya esta con ese formato en coambio el Datareader es un lector “bobo” no sabe lo que lee ni lo adsorbe de la base asi que pues me quedo con LINQ.!

  9. Seria bueno hacer un test pero con 300 millones de registros, creo que 10,000 no es mucho, actualmente donde trabajo contamos con esta cantidad de registros y los test ques estoy hacindo son lentos
    saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *