Recentemente, atualizei para o VS 2010 e estou brincando com LINQ to Dataset. Eu tenho um forte conjunto de dados tipado para autorização que está em HttpCache de um ASP.NET WebApplication.
Queria saber qual é a maneira mais rápida de verificar se um usuário está autorizado a fazer algo. Aqui está meu modelo de dados e algumas outras informações caso alguém esteja interessado.
Eu verifiquei 3 maneiras:
- banco de dados direto
- Consulta LINQ com condições Where como "Join" - Sintaxe
- Consulta LINQ com Join - Sintaxe
Estes são os resultados com 1000 chamadas em cada função:
1.Iteração:
- 4.2841519 seg.
- 115,7796925 seg.
- 2.024749 seg.
2.Iteração:
- 3,1954857 seg.
- 84.97047 seg.
- 1.5783397 seg.
3.Iteração:
- 2,7922143 seg.
- 97.8713267 seg.
- 1,8432163 seg.
Média:
- Banco de dados: 3,4239506333 seg.
- Onde: 99.5404964 seg.
- Unir: 1.815435 seg.
Por que a versão Join é muito mais rápida do que a sintaxe where, o que a torna inútil, embora, para um novato do LINQ, ela pareça ser a mais legível. Ou eu perdi algo em minhas consultas?
Aqui estão as consultas LINQ, eu pulo o banco de dados:
Onde :
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
Junte-se:
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
Agradeço antecipadamente.
Editar : depois de algumas melhorias em ambas as consultas para obter valores de desempenho mais significativos, a vantagem do JOIN é ainda muitas vezes maior do que antes:
Junte - se :
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
Onde :
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
Resultado para 1000 chamadas (em um computador mais rápido)
- Junte-se | 2. Onde
1.Iteração:
- 0,0713669 seg.
- 12,7395299 seg.
2.Iteração:
- 0,0492458 seg.
- 12,3885925 seg.
3.Iteração:
- 0,0501982 seg.
- 13,3474216 seg.
Média:
- União: 0,0569367 seg.
- Onde: 12,8251813 seg.
Participe 225 vezes mais rápido
Conclusão: evite WHERE para especificar relações e use JOIN sempre que possível (definitivamente em LINQ to DataSet e Linq-To-Objects
em geral).
Join
custa nada usar , por que confiar em um otimizador se você pode escrever o código otimizado desde o início? Também torna suas intenções mais claras. Portanto, as mesmas razões pelas quais você deve preferir JOIN no sql .