我有一个表格可以保留朋友的信息,列MemberID
和FriendID
。以下是一些示例数据:
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查询以完成任务。
答案 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
现在要反驳自己 - 我想到了这一点。关于扫描的说法只有在没有索引的情况下才有效。但是,如果MemberID
和FriendID
上都有单独的索引(一个是群集的,另一个是非群集的),那么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次搜索,性能最佳。