2013-02-27 55 views
3

我有一張表來保存好友信息,其中列MemberIDFriendID。下面是一些示例數據:用於在單個事務中獲取數據的SQL查詢

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

例如:

  • 的朋友MemberID 10 12,13,14,15
  • 的朋友MemberID 14 10,12

我已經嘗試了許多通過查詢獲取值的方式,但都是徒勞的。

請建議最好的SQL查詢來完成單個語句中的任務。

回答

3

這將需要掃描一次。沒有必要做一個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

現在爲了反駁我自己 - 我想到了這一點。我的關於掃描的說法只有在沒有索引的情況下才是真實的。但是,如果在MemberIDFriendID(其中一個是集羣,另一個是非集羣)上有單獨的索引,那麼實際上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個尋求,表現最好。

+1

有趣的是:通過這個查詢,完全是偶然的,我知道SQL Server會從*一個VALUES子句*(不僅僅是一個SELECT子句)推斷列名。哇!我不知道它可以做到這一點。驚人! – ErikE 2013-02-27 06:55:27

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,你正在尋找對於。

+0

這將正常工作。 – 2013-02-27 06:44:26