为用户友谊设计数据库
Posted
技术标签:
【中文标题】为用户友谊设计数据库【英文标题】:Designing A Database For User Friendship 【发布时间】:2012-12-28 01:39:21 【问题描述】:我想将友谊存储在数据库中。我的想法是,当 user1 与 user2 成为朋友时,我会存储该友谊,以便在需要时可以获取任一用户的所有朋友。起初我以为我只需将他们的 id 存储在一个插入的表中,但后来我在查询数据库时想到了一些复杂性。
如果我有 2 个用户 ID 分别为 10 和 20 的用户,当他们成为朋友时,我是否应该在数据库中插入两次
ID USER1 USER2
1 10 20
2 20 10
或者如果我只像这样插入一个,是否有办法查询数据库以仅获取特定用户的朋友
ID USER1 USER2
1 10 20
我知道第一种方法绝对可以满足我的需求,但我想知道这是否是一种好的做法以及是否有更好的选择。如果可以查询第二种方法来获得我想要的结果,就像用户 10 的所有朋友一样。
【问题讨论】:
user1 > user2
可以用作决胜局。或user1 < user2
...
【参考方案1】:
Brad Christie 关于双向查询表的建议很好。
但是,鉴于 mysql 不太擅长优化 OR
查询,使用 UNION ALL
可能更有效:
( SELECT u.id, u.name
FROM friendship f, user u
WHERE f.user1 = 1 AND f.user2 = u.id )
UNION ALL
( SELECT u.id, u.name
FROM friendship f, user u
WHERE f.user2 = 1 AND f.user1 = u.id )
Here's a SQLFiddle of it,基于 Brad 的示例。我修改了friendship
表以添加双向索引以实现高效访问,并删除了meaningless id
column。当然,用这么小的例子你不能真正测试真实世界的性能,但是比较两个版本之间的执行计划可能是有启发性的。
【讨论】:
快速提问。我不能只使用 Union 而不是 Union All 吗?因为这里不应该有任何重复对吧? 可以,但是UNION
要求 MySQL 实际检查重复项并在有重复项时将其删除。如果您知道无论如何都不会重复,UNION ALL
通常更快。
很好的建议,谢谢。 &将如何限制工作?就像我只想要 10 个朋友一样。如果我为每个选择添加限制 0,10 会返回 10 还是 20?有没有办法只交 10 个朋友?
您可以在整个联合中添加LIMIT
子句。但是,请注意there might be performance issues。 (我不确定这些问题是否也适用于没有LIMIT
而没有ORDER BY
的LIMIT
,无论如何,MySQL 版本之间可能存在差异。试试看。)当然,另一个(丑陋的)选项,就是将LIMIT
s 添加到个人SELECT
s 并在客户端丢弃任何不需要的额外行。
没有真正的区别:SELECT * FROM foo JOIN bar ON foo.x = bar.y
和 SELECT * FROM foo, bar WHERE foo.x = bar.y
都产生相同的输出和相同的查询计划。我自己通常更喜欢JOIN
... ON
样式,但是在这种情况下,我觉得使用另一种样式看起来更好,并且使两个子查询之间的对称性更加明显。 Here's a very nice explanation of the different styles.【参考方案2】:
友谊是双向的纽带(出于所有意图和目的)。与另一个链接(例如单向消息)不同,友谊应该只有一个条目。但是,您所看到的是正确的;您需要查询这两个列来获取用户的朋友,但这很简单:
-- The uses of `1` below is where you'd insert the ID of
-- the person you're looking up friends on
SELECT u.id, u.name
FROM friendship f
LEFT JOIN user u
ON (u.id = f.user1 OR u.id = f.user2)
AND u.id <> 1
WHERE (f.user1 = 1 OR f.user2 = 1)
example here
【讨论】:
以上是关于为用户友谊设计数据库的主要内容,如果未能解决你的问题,请参考以下文章
“科大讯飞杯”第十七届同济大学程序设计预选赛暨高校网络友谊赛 C 张老师的旅行