101

私は最近 VS 2010 にアップグレードし、LINQ to Dataset で遊んでいます。ASP.NET WebApplication の HttpCache にある Authorization 用の厳密に型指定されたデータセットがあります。

だから私は、ユーザーが何かをする権限があるかどうかを実際に確認する最も速い方法は何かを知りたいと思っていました. これが私のデータモデルと、誰かが興味を持っている場合のその他の情報です。

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

  1. 直接データベース
  2. Where条件を「結合」として使用する LINQ クエリ- 構文
  3. Joinを使用した 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 秒。

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. ここで: 12,8251813 秒。

Join は 225 倍高速です

結論: WHERE を使用してリレーションを指定することは避け、可能な限り JOIN を使用します ( LINQ to DataSetおよびLinq-To-Objects一般的には間違いなく)。

4

3 に答える 3

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

  2. 複数のテーブルとWhere条件を含むクエリは、実際にはすべてのテーブルのデカルト積を実行してから、条件を満たす行フィルター処理します。これは、Where行の各組み合わせ (n1 * n2 * n3 * n4) に対して条件が評価されることを意味します。

  3. 演算子は最初のJoinテーブルから行を取得し、次に 2 番目のテーブルから一致するキーを持つ行のみを取得し、次に 3 番目のテーブルから一致するキーを持つ行のみを取得する、というように続きます。多くの操作を実行する必要がないため、これははるかに効率的です。

于 2011-04-05T12:06:20.487 に答える
19

Joinメソッドはテーブルを組み合わせて結果を関連する組み合わせに減らす方法を知っているため、はるかに高速です。を使用Whereして関係を指定する場合、考えられるすべての組み合わせを作成し、条件をテストして、どの組み合わせが関連しているかを確認する必要があります。

このJoinメソッドは、2 つのテーブルをすばやく圧縮するためのインデックスとして使用するハッシュ テーブルを設定できますが、Whereメソッドはすべての組み合わせが既に作成された後に実行されるため、事前に組み合わせを減らすためのトリックを使用することはできません。

于 2011-04-05T11:56:14.397 に答える
7

本当に知っておく必要があるのは、2 つのステートメント用に作成された SQL です。アクセスする方法はいくつかありますが、最も簡単なのは LinqPad を使用することです。SQL に変更されるクエリ結果のすぐ上にいくつかのボタンがあります。そうすれば、何よりも多くの情報を得ることができます。

しかし、あなたがそこで共有した素晴らしい情報。

于 2011-04-05T11:56:50.957 に答える