これには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フィドルで機能していることを確認してください。
今、私自身と矛盾するために-私はこれについてもう少し考えました。スキャンに関する私の説明は、インデックスがない場合にのみ当てはまります。ただし、との両方に個別のインデックスがある場合MemberID
(FriendID
一方がクラスター化され、もう一方が非クラスター化)、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つのシークを取得し、パフォーマンスが最高になります。