3

友達情報を保持するためのテーブルがあり、列MemberIDFriendID。サンプルデータは次のとおりです。

RecordID MemberID FriendID
-------- -------- --------
   1        10       12    
   2        12       10    
   3        10       14    
   4        15       10    
   5        14       12    
   6        10       13    
   7        11       13

MemberIDコラムまたはコラムのいずれかで、メンバーの友達を見つける必要がありFriendIDます。

例えば:

  • 10人の友達は12、13、14、15MemberIDです。
  • 14の友達MemberIDは10、12です。

クエリで値を取得する方法をたくさん試しましたが、すべて無駄でした。

1つのステートメントでタスクを実行するための最適なSQLクエリを提案してください。

4

2 に答える 2

4

ユニオンでクエリを試しましたか?

SELECT FriendID
FROM mytable
WHERE MemberID = {The ID}
UNION
SELECT MemberID AS FriendID
FROM mytable
WHERE FriendID = {The ID}

区別する必要があり、重複する可能性がある場合は、次を使用することもできます。

SELECT DISTINCT FriendID
FROM (
    SELECT FriendID
    FROM mytable
    WHERE MemberID = {The ID}
    UNION
    SELECT MemberID AS FriendID
    FROM mytable
    WHERE FriendID = {The ID}
) Derived

また、明確にするために{The ID}、探しているIDに必ず置き換えてください。

于 2013-02-27T06:38:27.760 に答える
3

これには1回のスキャンが必要です。--を実行する必要はありません。これUNIONには2回のスキャンが必要であり、パフォーマンスが低下します。

SELECT DISTINCT
   M.FriendID
FROM
   dbo.Friend F
   CROSS APPLY (VALUES
      (F.MemberID, F.FriendID),
      (F.FriendID, F.MemberID)
   ) M
WHERE
   M.MemberID = 10;

これがSQLフィドルで機能していることを確認してください

今、私自身と矛盾するために-私はこれについてもう少し考えました。スキャンに関する私の説明は、インデックスがない場合にのみ当てはまります。ただし、との両方に個別のインデックスがある場合MemberIDFriendID一方がクラスター化され、もう一方が非クラスター化)、UNIONスキャンの代わりに2つのシークを実行するため、メソッドのパフォーマンスは実際に向上します。UNIONしたがって、このため、実際には、これらのインデックスを維持して実行することをお勧めします。

SELECT FriendID FROM dbo.Friend WHERE MemberID = 10
UNION
SELECT MemberID FROM dbo.Friend WHERE FriendID = 10;

さらに、どのクエリを選択しても、テーブルRecordIDから列を削除することをお勧めしFriendます。友達同士の関係を参照したいときはいつでも、の複合キーを使用するだけなので、この列はまったく不要です(MemberID, FriendID)。この列を削除することにより、各行にかかるバイト数が少なくなり、ページあたりの行数が増え、同じデータを取得するための読み取りが少なくなり、パフォーマンスが向上します。テーブルに他の列がない場合は、削除することで1ページあたりの行数が50%多くなりますRecordID

これらの推奨事項を実装する方法は次のとおりです。

-- if RecordID is part of the PK
ALTER TABLE dbo.Friend DROP CONSTRAINT PK_Whatever;

-- if RecordID is part of a separate non-PK clustered index
DROP INDEX dbo.Friend.CI_Whatever;

-- If the PK is not already over these two columns
ALTER TABLE dbo.Friend
   ADD CONSTRAINT PK_Friend PRIMARY KEY CLUSTERED (MemberID, FriendID);

CREATE NONCLUSTERED INDEX IX_Friend_FriendID_MemberID
   ON dbo.Friend (FriendID) -- MemberID is implicitly included.

最終的な非クラスター化インデックスは、UNION上記のクエリの2番目の部分の「カバー」インデックスになりました。つまり、クエリのその部分を満たすためにクラスター化インデックスをヒットする必要はありません。したがって、2つのシークを取得し、パフォーマンスが最高になります。

于 2013-02-27T06:46:10.800 に答える