Recientemente me actualicé a VS 2010 y estoy jugando con LINQ to Dataset. Tengo un sólido conjunto de datos tipeados para la autorización que se encuentra en HttpCache de una aplicación web ASP.NET.
Así que quería saber cuál es la forma más rápida de comprobar si un usuario está autorizado a hacer algo. Aquí está mi modelo de datos y algunas otras informaciones si alguien está interesado.
He verificado 3 formas:
Estos son los resultados con 1000 llamadas en cada función:
1.Interación:
2.Interación:
3.Interación:
Promedio:
¿Por qué la Join-versión es mucho más rápida que la syntax where, lo que la hace inútil, aunque como novato LINQ parece ser la más legible. ¿O me he perdido algo en mis consultas?
Aquí están las consultas LINQ, me salteo la base de datos:
Donde :
Public Function hasAccessDS_Where(ByVal accessRule As String) As Boolean Dim userID As Guid = DirectCast(Membership.GetUser.ProviderUserKey, Guid) Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule, _ roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule, _ role In Authorization.dsAuth.aspnet_Roles, _ userRole In Authorization.dsAuth.aspnet_UsersInRoles _ Where accRule.idAccessRule = roleAccRule.fiAccessRule _ And roleAccRule.fiRole = role.RoleId _ And userRole.RoleId = role.RoleId _ And userRole.UserId = userID And accRule.RuleName.Contains(accessRule) Select accRule.idAccessRule Return query.Any End Function
Unirse:
Public Function hasAccessDS_Join(ByVal accessRule As String) As Boolean Dim userID As Guid = DirectCast(Membership.GetUser.ProviderUserKey, Guid) Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule _ Join roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule _ On accRule.idAccessRule Equals roleAccRule.fiAccessRule _ Join role In Authorization.dsAuth.aspnet_Roles _ On role.RoleId Equals roleAccRule.fiRole _ Join userRole In Authorization.dsAuth.aspnet_UsersInRoles _ On userRole.RoleId Equals role.RoleId _ Where userRole.UserId = userID And accRule.RuleName.Contains(accessRule) Select accRule.idAccessRule Return query.Any End Function
Gracias de antemano.
Editar : después de algunas mejoras en ambas consultas para obtener valores de rendimiento más significativos, la ventaja de JOIN es incluso muchas veces mayor que antes:
Únete :
Public Overloads Shared Function hasAccessDS_Join(ByVal userID As Guid, ByVal idAccessRule As Int32) As Boolean Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule _ Join roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule _ On accRule.idAccessRule Equals roleAccRule.fiAccessRule _ Join role In Authorization.dsAuth.aspnet_Roles _ On role.RoleId Equals roleAccRule.fiRole _ Join userRole In Authorization.dsAuth.aspnet_UsersInRoles _ On userRole.RoleId Equals role.RoleId _ Where accRule.idAccessRule = idAccessRule And userRole.UserId = userID Select role.RoleId Return query.Any End Function
Donde :
Public Overloads Shared Function hasAccessDS_Where(ByVal userID As Guid, ByVal idAccessRule As Int32) As Boolean Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule, _ roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule, _ role In Authorization.dsAuth.aspnet_Roles, _ userRole In Authorization.dsAuth.aspnet_UsersInRoles _ Where accRule.idAccessRule = roleAccRule.fiAccessRule _ And roleAccRule.fiRole = role.RoleId _ And userRole.RoleId = role.RoleId _ And accRule.idAccessRule = idAccessRule And userRole.UserId = userID Select role.RoleId Return query.Any End Function
1.Interación:
2.Interación:
3.Interación:
Promedio:
Unirse es 225 veces más rápido
Conclusión: evite DONDE especificar relaciones y use JOIN siempre que sea posible (definitivamente en LINQ to DataSet y Linq-To-Objects
en general).
Su primer enfoque (consulta SQL en el DB) es bastante eficiente porque el DB sabe cómo realizar un join. Pero realmente no tiene sentido compararlo con los otros enfoques, ya que funcionan directamente en la memoria (Linq a DataSet)
La consulta con varias tablas y una condición Where
realiza un producto cartesiano de todas las tablas, luego filtra las filas que satisfacen la condición. Esto significa que la condición Where
se evalúa para cada combinación de filas (n1 * n2 * n3 * n4)
El operador de Join
toma las filas de las primeras tablas, luego toma solo las filas con una clave coincidente de la segunda tabla, luego solo las filas con una clave coincidente de la tercera tabla, y así sucesivamente. Esto es mucho más eficiente, porque no necesita realizar tantas operaciones
La Join
es mucho más rápida, porque el método sabe cómo combinar las tablas para reducir el resultado a las combinaciones correspondientes. Cuando usa Where
especificar la relación, tiene que crear todas las combinaciones posibles, y luego probar la condición para ver qué combinaciones son relevantes.
El método Join
puede configurar una tabla hash para usar como índice para comprimir rápidamente dos tablas juntas, mientras que el método Where
se ejecuta después de que todas las combinaciones ya estén creadas, por lo que no puede usar ningún truco para reducir las combinaciones de antemano.
lo que realmente necesita saber es el sql que se creó para las dos declaraciones. Hay algunas maneras de llegar a ella, pero la más simple es usar LinqPad. Hay varios botones justo encima de los resultados de la consulta que cambiarán a sql. Eso le dará mucha más información que otra cosa.
Gran información que compartiste allí sin embargo.