[.net] LINQ JOIN이 WHERE와 연결하는 것보다 훨씬 빠른 이유는 무엇입니까?

최근에 VS 2010으로 업그레이드했고 LINQ to Dataset을 가지고 놀았습니다. ASP.NET WebApplication의 HttpCache에있는 권한 부여를위한 강력한 형식의 데이터 집합이 있습니다.

그래서 저는 사용자가 무언가를 할 권한이 있는지 확인하는 가장 빠른 방법이 무엇인지 알고 싶었습니다. 누군가가 관심이 있다면 여기 내 데이터 모델과 다른 정보가 있습니다.

세 가지 방법을 확인했습니다.

  1. 직접 데이터베이스
  2. Where 조건이 “Join”인 LINQ 쿼리 -구문
  3. 조인을 사용한 LINQ 쿼리 -구문

다음은 각 함수에 대해 1000 번 호출 한 결과입니다.

1. 반복 :

  1. 4,2841519 초
  2. 115,7796925 초
  3. 2,024749 초

2. 반복 :

  1. 3,1954857 초
  2. 84,97047 초
  3. 1,5783397 초

3. 반복 :

  1. 2,7922143 초
  2. 97,8713267 초
  3. 1,8432163 초

평균:

  1. 데이터베이스 : 3,4239506333 초
  2. Where : 99,5404964 초
  3. 가입 : 1,815435 초

Join-version이 where-syntax보다 훨씬 빠른 이유는 LINQ 초보자로서 가장 읽기 쉬운 것처럼 보이지만 쓸모 없게 만듭니다. 아니면 내 질문에서 놓친 것이 있습니까?

다음은 LINQ 쿼리입니다. 데이터베이스를 건너 뜁니다.

어디에 :

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

붙다:

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

미리 감사드립니다.


편집 : 더 의미있는 성능 값을 얻기 위해 두 쿼리를 약간 개선 한 후 JOIN의 이점은 이전보다 훨씬 더 큽니다.

가입 :

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

어디에 :

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

1000 번의 통화 결과 (빠른 컴퓨터에서)

  1. 가입 | 2. 어디서

1. 반복 :

  1. 0,0713669 초
  2. 12,7395299 초

2. 반복 :

  1. 0,0492458 초
  2. 12,3885925 초

3. 반복 :

  1. 0,0501982 초
  2. 13,3474216 초

평균:

  1. 가입 : 0,0569367 초
  2. Where : 12,8251813 초

가입 속도가 225 배 빠릅니다.

결론 : 관계를 지정하기 위해 WHERE를 피하고 가능할 때마다 JOIN을 사용하십시오 (확실히 LINQ to DataSetLinq-To-Objects일반적으로).



답변

  1. 첫 번째 방법 (DB의 SQL 쿼리)은 DB가 조인을 수행하는 방법을 알고 있기 때문에 매우 효율적입니다. 그러나 메모리에서 직접 작동하기 때문에 다른 접근 방식과 비교하는 것은 실제로 의미가 없습니다 (Linq에서 DataSet로).

  2. 여러 테이블과 Where조건 이있는 쿼리는 실제로 모든 테이블 의 데카르트 곱을 수행 한 다음 조건을 충족하는 행 필터링합니다. 즉, Where각 행 조합 (n1 * n2 * n3 * n4)에 대해 조건이 평가됩니다.

  3. Join운영자는 제 테이블에서 매칭 키 행만 등 번째 테이블에서 매칭 키 만 행을 얻어 다음, 제 테이블의 행 걸린다. 많은 작업을 수행 할 필요가 없기 때문에 훨씬 더 효율적입니다.


답변

Join방법은 테이블을 결합하여 결과를 관련 조합으로 줄이는 방법을 알고 있기 때문에 훨씬 빠릅니다. 당신이 사용하는 경우 Where의 관계를 지정하기 위해서는 가능한 모든 조합을 만든 다음 관련있는 조합을 볼 수있는 조건을 테스트 할 수 있습니다.

Join메서드는 두 테이블을 빠르게 압축하는 인덱스로 사용할 해시 테이블을 설정할 수 있으며, Where모든 조합이 이미 생성 된 후에 메서드가 실행되므로 사전에 조합을 줄이는 트릭을 사용할 수 없습니다.


답변

당신이 정말로 알아야 할 것은 두 문장을 위해 만들어진 SQL이다. 몇 가지 방법이 있지만 가장 간단한 방법은 LinqPad를 사용하는 것입니다. 쿼리 결과 바로 위에 SQL로 변경되는 몇 가지 버튼이 있습니다. 그것은 당신에게 다른 무엇보다 더 많은 정보를 줄 것입니다.

그래도 훌륭한 정보를 공유했습니다.


답변