我需要显示帖子列表。对于每篇文章,我还需要展示:
我不知道如何在不查询for循环中的每个项目的情况下这样做,这被证明是非常慢的。确定缓存/非规范化会有所帮助,但我想知道是否可以这样做。 facebook是如何做到的?
假设这个基本的db结构,有什么建议吗?
users
-----
id
username
posts
---------
id
user_id
content
friendships
-----------
user_id
friend_id
is_confirmed (bool)
users_liked_posts
-----------------
user_id
post_id
作为旁注,如果有人知道如何在SQLAlchemy中执行此操作,那将非常感激。
编辑:SQLFiddle http://sqlfiddle.com/#!2/9e703
答案 0 :(得分:2)
您可以在sqlfiddle中尝试此操作。条件" WHERE user_id = 2"需要2替换为您当前的用户ID。
SELECT numbered.*
FROM
(SELECT ranked.*,
IF (post_id=@prev_post,
@n := @n + 1,
@n := 1 AND @prev_post := post_id) as position
FROM
(SELECT users_liked_posts.post_id,
users_liked_posts.user_id,
visitor.user_id as u1,
friendships.user_id as u2,
IF (visitor.user_id is not null, 1, IF(friendships.user_id is not null, 2, 3)) as rank
FROM users_liked_posts
INNER JOIN posts
ON posts.id = users_liked_posts.post_id
LEFT JOIN friendships
ON users_liked_posts.user_id = friendships.user_id
AND friendships.friend_id = posts.user_id
LEFT JOIN (SELECT post_id, user_id FROM users_liked_posts WHERE user_id = 2) visitor
ON users_liked_posts.post_id = visitor.post_id
AND users_liked_posts.user_id = visitor.user_id
ORDER BY users_liked_posts.post_id, rank) as ranked
JOIN
(SELECT @n := 0, @prev_post := 0) as setup) as numbered
WHERE numbered.position < 4
您可以轻松加入子查询&#34;编号&#34;与表&#34;用户&#34;获取其他用户信息。还有额外的字段u2,u3来帮助查看正在发生的事情。你可以删除这些。
查询的一般概念:
1)左右加入users_liked_posts两次。第一次限制为当前访问者,创建子查询访问者。第二次仅限于朋友。
2)列排名IF(visitor.user_id不为空,1,IF(friendships.user_id不为空,2,3)),为users_liked_posts中的每个用户分配排名。此查询按帖子和排名进行排序。
3)使用前一个作为子查询来创建相同的数据,但每个帖子都有用户的运行位置。
4)使用前一个作为子查询来提取每个帖子的前3个位置。
不,这些步骤无法合并,特别是因为MySQL不允许WHERE条件中的别名使用计算列。
答案 1 :(得分:1)
我可能会建议您使用图形数据库,而不是RDBS,例如neo4j
祝你好运。修改强>
如果您对使用Neo4j感兴趣,那么你真的不得不玩Neo4j。您可能会或可能不会发现更容易来自SQL背景,但它肯定会提供更强大的,以及可能更快的查询来执行图形遍历。
以下是一些可能对您有用的Cypher查询示例。
统计有多少人喜欢帖子:
START post=node({postId})
MATCH post<-[:like]-user
RETURN count(*)
(实际上你应该使用一个原子计数器,相反,如果它是你将要查询的东西)
获得三个喜欢帖子的人 ,其中包含以下限制条件:
likingUser
将始终是当前用户。START post=node({postId}), user=node({currentUserId}) MATCH path = post<-[:like]-likingUser-[r?:friend*0..1]-user RETURN likingUser, count(r) as rc, length(path) as len ORDER BY rc desc, len asc LIMIT 3
我会尝试解释上面的问题...如果可以的话。
post
和当前user
likingUser
)likingUser
通过友谊关系连接到当前user
(长度为0的路径表示likingUser==user
)。r
是否存在来排序结果(如果likingUser
是与user
或likingUser==user
的朋友,则会存在。因此,count(r)
对于每个结果将为0或1。由于我们更喜欢count(r)==1
的结果,因此我们将按降序对其进行排序。user
到列表顶部。我们通过检查path
的长度来做到这一点。当user==likingUser
时,路径长度将短于user
成为likingUser
的朋友时的路径长度,因此我们可以使用length(path)
强制user
到达顶部按升序排序。希望这有点道理。作为旁注,通过分离查询,您实际上可以获得更好的性能。例如,一个查询以查看用户是否喜欢该帖子,然后另一个查询以获得最多三个喜欢该帖子的朋友,最后另一个查询以获得最多三个喜欢该帖子的非朋友。我说它可能更快,因为每个查询在得到三个结果后都会短路,而我写的大单查询必须考虑所有可能性,然后对它们进行排序。所以,请记住,仅仅因为您可以将多个问题组合到一个查询中,它实际上可能比多个查询更糟糕。