1. ホーム
  2. .net

[解決済み] なぜLINQ JOINはWHEREでリンクするよりもずっと速いのですか?

2022-12-27 14:07:22

質問

最近 VS 2010 にアップグレードし、LINQ to Dataset を使って遊んでいます。私はASP.NET WebApplicationのHttpCacheにある認証のための強い型付けされたデータセットを持っています。

そこで私は、ユーザーが何かをすることを許可されているかどうかを確認する最も速い方法は何であるかを知りたいと思いました。 ここで は私のデータモデルと他の情報です。

私は3つの方法をチェックしました。

  1. 直接 データベース
  2. LINQクエリで ここで を条件とする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. 場所 99,5404964 秒
  3. 結合: 1,815435 秒。

LINQ初心者としては最も読みやすいと思われますが、なぜJoinバージョンはwhere-syntaxよりもずっと速いのでしょうか。それとも、私のクエリに何か見落としがあったのでしょうか?

以下は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の利点は以前の何倍も大きくなりました。

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.Iteration。

  1. 0,0713669秒。
  2. 12,7395299 秒

2.イテレーション

  1. 0,0492458秒。
  2. 12,3885925 秒

3.イテレーション

  1. 0,0501982秒。
  2. 13,3474216 秒

平均値です。

  1. 参加: 0,0569367 秒。
  2. どこで 12,8251813 秒

ジョインが225倍高速化

結論 リレーションを指定するためにWHEREを避け、可能な限りJOINを使用する(間違いなく LINQからDataSet Linq-To-Objects を一般に)使用することができます。

どのように解決するのですか?

  1. 最初のアプローチ(DBでのSQLクエリ)は、DBが結合を実行する方法を知っているので、非常に効率的です。しかし、他のアプローチはメモリ内で直接動作するため(Linq to DataSet)、これを比較するのはあまり意味がありません。

  2. 複数のテーブルを持つクエリと Where 条件を持つクエリは、実際には カルテジアン積 を実行します。 では は条件を満たす行をフィルタリングします。これはつまり Where の条件は、行の各組み合わせ(n1 * n2 * n3 * n4)に対して評価されます。

  3. Join 演算子は最初のテーブルから行を取り出し、次に 2 番目のテーブルからキーが一致する行だけを取り出し、さらに 3 番目のテーブルからキーが一致する行だけを取り出し、といった具合になります。これは、それほど多くの処理を行う必要がないため、より効率的です。