這將需要掃描一次。沒有必要做一個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;
See this working in a Sql Fiddle。
現在爲了反駁我自己 - 我想到了這一點。我的關於掃描的說法只有在沒有索引的情況下才是真實的。但是,如果在MemberID
和FriendID
(其中一個是集羣,另一個是非集羣)上有單獨的索引,那麼實際上UNION
方法的性能會更好,因爲它將執行兩次搜索而不是掃描。所以正因爲如此,我實際上建議你堅持UNION
並讓這些索引進行。
SELECT FriendID FROM dbo.Friend WHERE MemberID = 10
UNION
SELECT MemberID FROM dbo.Friend WHERE FriendID = 10;
此外,我建議無論哪個查詢您選擇,您從Friend
表中刪除RecordID
列。這一欄是完全不必要的,因爲任何時候你想引用朋友之間的關係,你都可以簡單地使用(MemberID, FriendID)
的組合鍵。通過刪除這一列,每行將佔用較少的字節數,這將獲得每頁更多的行,這將導致讀取次數更少以獲得相同的數據 - 這是性能提升的勝利。如果表格中沒有其他列,則通過刪除RecordID
,您將獲得每頁50%以上的行數!
這裏是你如何可以實現這些建議:
-- 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個尋求,表現最好。
有趣的是:通過這個查詢,完全是偶然的,我知道SQL Server會從*一個VALUES子句*(不僅僅是一個SELECT子句)推斷列名。哇!我不知道它可以做到這一點。驚人! – ErikE 2013-02-27 06:55:27