Entre Códigos


El blog de Rubén Cantón

Reflexiones de un cerebro en fuga y artículos sobre posicionamiento, e-marketing, usabilidad y otros tecnicismos.

greyimg

Probando el rendimiento de LINQ en ASP.Net

Escrito por Ruben Cantón el Friday, 3 de July del 2009
Más del mismo tema: laboratorio, taller

LINQ
Después de haber aprendido lo que es LINQ y cómo funciona, es obligado ver si, además de simplificar el código, mejora la eficiencia de nuestro proyecto.

Me he decidido por probar la lectura de archivos XML por parte de LINQ y determinar quien tiene mayor velocidad de lectura, la librería de acceso a XML de .Net o la nueva tecnología: LINQ. Para ello, he creado un XML con 100.000 registros que simula una tabla de alumnos y realizaré consultas a dicho XML.

Éstas son las consultas que he decidido realizar utilizando ambos sistemas:

  • Prueba 1: Extraer todos los alumnos que se llamen Jorge.
  • Prueba 2: Contar cuantos alumnos han aprobado.
  • Prueba 3: De entre los alumnos que se llaman Jorge, ¿cuántos han suspendido?
  • Prueba 4: De entre los alumnos que han sacado más de un 8, ¿cual es el nombre más predominante?
  • Prueba 5: Extraer sólo los nombres distintos de los alumnos y ordenarlos..

Y tras lanzar las mismas aquí están, en segundos, los tiempos que ha tardado cada método en cada una de las consultas anteriores:

Prueba XML Reader LINQ
1 0,301934 0,000036
2 0,589991 0,090168
3 0,390582 0,054944
4 0,432305 0,091441
5 0,281885 0,042886

Se puede apreciar claramente la diferencia en velocidades de acceso, siendo el XML Reader entre 7 y 8 veces más lento que LINQ. Pero además, las consultas en LINQ me han ocupado entre 1 y 3 líneas (y porque he querido dividirlo en líneas) mientras que las realizadas con el antiguo método ocupaban entre 10 y 30 líneas.

Por todo esto, LINQ parece batir al XML Reader tanto en velocidad de acceso como en simplificación de código, lo que reduce errores y costes de producción o mantenimiento.

Sé que existen otros métodos para acceder a un XML en .Net (la librería de XML ofrece otras opciones), pero yo me he decantado por ésta, quizás alguna otra resultase más eficiente, pero tras realizar varias pruebas con LINQ, realmente me ha convencido como tecnología de acceso a conjuntos de datos.

Por último, dejo aquí el código fuente utilizado, por si a alguien le pica la curiosidad o he metido la pata y alguien puede corregirme:

    Private Sub TestVelocidad1()
Dim rutaArchivo As String = "C:/test/xmlAlumnos100.xml"
Dim metodoReader As System.Xml.XmlTextReader
Dim metodoLINQ As System.Xml.Linq.XDocument = System.Xml.Linq.XDocument.Load(rutaArchivo)
Dim lstAlumnos As New Collections.Generic.List(Of Alumno)
Dim lstNombres As New Collections.Generic.List(Of String)
Dim oAlumno As Alumno = Nothing
Dim notaAux As Byte = 0
Dim cantAprobados As Integer = 0
Dim cantSuspendidos As Integer = 0

Page.Trace.IsEnabled = True

'Prueba 1: Extraer todos los alumnos que se llamen Jorge.
Trace.Warn("Empieza la prueba 1")
Dim alumnos = From alum In metodoLINQ.Descendants("alumno") _
Where alum.Attribute("nombre") IsNot Nothing AndAlso alum.Attribute("nombre").Value = "Jorge" _
Select Nombre = alum.Attribute("nombre").Value, Nota = alum.Attribute("nota").Value
Trace.Warn("Fin prueba 1 con LINQ")

metodoReader = New System.Xml.XmlTextReader(rutaArchivo)
Do While metodoReader.Read
If metodoReader.NodeType = System.Xml.XmlNodeType.Element AndAlso metodoReader.Name = "alumno" AndAlso metodoReader.HasAttributes Then
oAlumno = New Alumno
While metodoReader.MoveToNextAttribute
If metodoReader.Name = "nombre" Then
oAlumno.Nombre = metodoReader.Value
If oAlumno.Nombre <> "Jorge" Then Exit While
ElseIf metodoReader.Name = "nota" Then
Byte.TryParse(metodoReader.Value, oAlumno.Nota)
End If
End While
If oAlumno.Nombre = "Jorge" Then lstAlumnos.Add(oAlumno)
End If
Loop
Trace.Warn("Fin prueba 1 con Reader")

'Prueba 2: Contar cuantos alumnos han aprobado.
Trace.Warn("Empieza la prueba 2")
cantAprobados = (From alum In metodoLINQ.Descendants("alumno") Where alum.Attribute("nota") IsNot Nothing AndAlso Integer.Parse(alum.Attribute("nota").Value) > 4).Count
Trace.Warn("Fin prueba 2 con LINQ")

metodoReader = New System.Xml.XmlTextReader(rutaArchivo)
cantAprobados = 0
Do While metodoReader.Read
If metodoReader.NodeType = System.Xml.XmlNodeType.Element AndAlso metodoReader.Name = "alumno" AndAlso metodoReader.HasAttributes Then
notaAux = 0
While metodoReader.MoveToNextAttribute
If metodoReader.Name = "nota" Then
Byte.TryParse(metodoReader.Value, notaAux)
If notaAux > 4 Then cantAprobados += 1
End If
End While
End If
Loop
Trace.Warn("Fin prueba 2 con Reader")

'Prueba 3: De entre los alumnos que se llaman Jorge, ¿cuántos han suspendido?
Trace.Warn("Empieza la prueba 3")
cantSuspendidos = (From alum In metodoLINQ.Descendants("alumno") _
Where alum.Attribute("nombre") IsNot Nothing AndAlso alum.Attribute("nombre").Value = "Jorge" _
Where alum.Attribute("nota") IsNot Nothing AndAlso Integer.Parse(alum.Attribute("nota").Value) < 5).Count
        Trace.Warn("Fin prueba 3 con LINQ")

        metodoReader = New System.Xml.XmlTextReader(rutaArchivo)
        cantSuspendidos = 0
        oAlumno = New Alumno
        Do While metodoReader.Read
            If metodoReader.NodeType = System.Xml.XmlNodeType.Element AndAlso metodoReader.Name = "alumno" AndAlso metodoReader.HasAttributes Then
                notaAux = 0 : oAlumno.Nombre = "" : oAlumno.Nota = 0
                While metodoReader.MoveToNextAttribute
                    If metodoReader.Name = "nota" Then Byte.TryParse(metodoReader.Value, oAlumno.Nota)
                    If metodoReader.Name = "nombre" Then oAlumno.Nombre = metodoReader.Value
                End While
                If oAlumno.Nombre = "Jorge" And oAlumno.Nota < 5 Then cantSuspendidos += 1
            End If
        Loop
        Trace.Warn("Fin prueba 3 con Reader")

        'Prueba 4: De entre los alumnos que han sacado más de un 8, ¿cual es el nombre más predominante?
        Dim NombreMasEmpollon As String = ""
        Trace.Warn("Empieza la prueba 4")

        Dim empollon As Generic.List(Of String) = (From n In (From alum In metodoLINQ.Descendants("alumno") _
            Where (alum.Attribute("nota") IsNot Nothing AndAlso Integer.Parse(alum.Attribute("nota").Value) > 8) _
            Group alum By nombre = alum.Attribute("nombre").Value Into cantNombres = Count() _
            Select nombre, cantNombres Order By cantNombres Descending Order By cantNombres Descending Take 1) Select n.nombre).ToList
        NombreMasEmpollon = empollon.Item(0).ToString
        Trace.Warn("Fin prueba 4 con LINQ")

        metodoReader = New System.Xml.XmlTextReader(rutaArchivo)
        Dim klstNombres As New Generic.SortedList(Of String, Integer)
        oAlumno = New Alumno
        Do While metodoReader.Read
            If metodoReader.NodeType = System.Xml.XmlNodeType.Element AndAlso metodoReader.Name = "alumno" AndAlso metodoReader.HasAttributes Then
                oAlumno.Nombre = "" : oAlumno.Nota = 0
                While metodoReader.MoveToNextAttribute
                    If metodoReader.Name = "nota" Then Byte.TryParse(metodoReader.Value, oAlumno.Nota)
                    If metodoReader.Name = "nombre" Then oAlumno.Nombre = metodoReader.Value

                    If oAlumno.Nota > 0 And oAlumno.Nombre.Length > 0 Then
                        If oAlumno.Nota > 8 Then
                            If klstNombres.Keys.IndexOf(oAlumno.Nombre) < 0 Then
                                klstNombres.Add(oAlumno.Nombre, 1)
                            Else
                                klstNombres.Item(oAlumno.Nombre) = klstNombres.Item(oAlumno.Nombre) + 1
                            End If
                        End If
                        Exit While
                    End If
                End While
            End If
        Loop
        NombreMasEmpollon = klstNombres.Keys(0)
        For Each n As String In klstNombres.Keys
            If klstNombres(n) > klstNombres(NombreMasEmpollon) Then
                NombreMasEmpollon = n
            End If
        Next
        Trace.Warn("Fin prueba 4 con Reader")

        'Prueba 5: Extraer sólo los nombres distintos de los alumnos y ordenarlos.
        Trace.Warn("Empieza la prueba 5")
        Dim nombres As String() = (From alum In metodoLINQ.Descendants("alumno") Select n = alum.Attribute("nombre").Value Distinct Order By n.ToString).ToArray
        Trace.Warn("Fin prueba 5 con LINQ")

        metodoReader = New System.Xml.XmlTextReader(rutaArchivo)
        lstNombres.Clear()
        Do While metodoReader.Read
            If metodoReader.NodeType = System.Xml.XmlNodeType.Element AndAlso metodoReader.Name = "alumno" AndAlso metodoReader.HasAttributes Then
                While metodoReader.MoveToNextAttribute
                    If metodoReader.Name = "nombre" Then
                        If lstNombres.IndexOf(metodoReader.Value) < 0 Then
                            lstNombres.Add(metodoReader.Value)
                        End If
                        Exit While
                    End If
                End While
            End If
        Loop
        lstNombres.Sort()
        Trace.Warn("Fin prueba 5 con Reader")

    End Sub

Public Class Alumno

#Region "Variables"
    Private _nombre As String
    Private _nota As Byte
#End Region

#Region "Propiedades"
    Public Property Nombre() As String
        Get
            Return _nombre
        End Get
        Set(ByVal value As String)
            _nombre = value
        End Set
    End Property
    Public Property Nota() As Byte
        Get
            Return _nota
        End Get
        Set(ByVal value As Byte)
            _nota = value
        End Set
    End Property
#End Region

End Class

Ya hay 2 comentarios. ¡Falta el tuyo!

Escríbe aquí tu opinión

Nombre (necesario)

Email (no se mostrará)

Web (opcional)

mygif
1. Galo
August 14th, 2009 at 5:00 pm

Muy buen analisis entre las dos opciones. !!!

Pingback y Trackback

Pingback y trackback de varios blogs:
August 28th, 2010 at 11:30 am

[...] post its a translation from my original post in spanish. I hope you enjoy [...]

¿Quieres más?

Temas del blog

Busca por Entre Códigos

 

Últimos comentarios

Últimos artículos

Lo más comentado

Blogroll

Mis proyectos