SQL Query在单个事务中获取数据

时间:2013-02-27 06:34:49

标签: sql sql-server-2008

我有一个表格可以保留朋友的信息,列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列中找到任何成员的朋友。

例如:

  • MemberID 10的朋友分别是12,13,14,15。
  • MemberID 14的朋友是10,12。

我尝试了很多方法来获取查询的值,但都是徒劳的。

请在单个语句中建议最佳SQL查询以完成任务。

2 个答案:

答案 0 :(得分: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。

答案 1 :(得分: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;

此外,我建议您无论选择哪个查询,都要从RecordID表中删除Friend列。此列完全没必要,因为只要您想要引用朋友之间的关系,您就可以使用(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次搜索,性能最佳。