我在编写查询时遇到问题,当他们的朋友共享多个朋友时,向我的最终用户推荐朋友。目前正在使用的架构远非最佳,但我的老板坚持认为我不允许改变表结构,即使我告诉他为朋友关系提供2列比一列快得多
我们目前每个友谊都有一对价值观:
friendID | Entity_ID1 | Entity_Id2
1 2 3
2 1 4
3 2 5
我知道对此列进行反转会使我的查询更加简单。到目前为止,我已经设计了以下查询来尝试为用户找到建议的朋友:
SELECT DISTINCT Entity_Id, Fb_Id, First_Name, Last_Name, Profile_Pic_Url, Last_CheckIn_Place, Category
FROM entity
JOIN friends F1
ON entity.Entity_Id = F1.Entity_Id2 OR entity.Entity_Id = F1.Entity_Id1
/* Friends of Friends */
WHERE F1.Entity_Id2 IN
(
SELECT Entity_Id1
FROM friends F
WHERE F.Entity_Id2 = :userId
AND F.Category != 4
UNION
SELECT Entity_Id2
FROM friends F
WHERE F.Entity_Id1 = :userId
AND F.Category != 4
)
/* Exclude my friends */
AND F1.Entity_Id1 NOT IN
(
SELECT Entity_Id1
FROM friends F
WHERE F.Entity_Id2 = :userId
AND F.Category != 4
UNION
SELECT Entity_Id2
FROM friends F
WHERE F.Entity_Id1 = :userId
AND F.Category != 4
)
/* Exclude self */
AND F1.Entity_Id1 != :userId
GROUP BY Entity_Id
/* Perform again for userId 2 */
UNION
SELECT DISTINCT Entity_Id, Fb_Id, First_Name, Last_Name, Profile_Pic_Url, Last_CheckIn_Place, Category
FROM entity
JOIN friends F2
ON entity.Entity_Id = F2.Entity_Id2 OR entity.Entity_Id = F2.Entity_Id1
WHERE F2.Entity_Id1 IN
(
SELECT Entity_Id1
FROM friends F
WHERE F.Entity_Id2 = :userId
AND F.Category != 4
UNION
SELECT Entity_Id2
FROM friends F
WHERE F.Entity_Id1 = :userId
AND F.Category != 4
)
/* Exclude my friends */
AND F2.Entity_Id2 NOT IN
(
SELECT Entity_Id1
FROM friends F
WHERE F.Entity_Id2 = :userId
AND F.Category != 4
UNION
SELECT Entity_Id2
FROM friends F
WHERE F.Entity_Id1 = :userId
AND F.Category != 4
)
AND F2.Entity_Id2 != :userId
GROUP BY Entity_Id
这种作品,然而它返回用户我已经是我不想要的朋友,我想通过为我的朋友使用NOT IN()子句,然后使用UNION合并结果,这将脱掉我的朋友,但显然没有。
我在这里做错了什么,是否有任何方法可以在不修改架构的情况下缩短查询时间,现在它看起来很长而且不易管理。
答案 0 :(得分:1)
错过互惠关系确实会让事情变得更加艰难。它需要检查关系的两个方向。您似乎正在寻求使用union
来重建关系双方的策略。
或者,您可以使用exists
和子查询。以下版本使用exists
找到不是朋友并且至少有两个朋友的实体:
select e.*
from entities e
where e.entity_id <> :user_id and
not exists (select 1
from friends f
where f.category <> 4 and
:user_id in (f.entity_id1, f.entity_id2) and
e.entity_id in (f.entity_id1, f.entity_id2)
) and
(select count(*)
from friends f1 join
friends f2
on f1.entity_id1 = f2.entity_id1 or
f1.entity_id1 = f2.entity_id2 or
f1.entity_id2 = f2.entity_id1 or
f1.entity_id1 = f2.entity_id2
where :user_id in (f1.entity_id1, f1.entity_id2, f2.entity_id1, f2.entity_id2) and
e.entity_id in (f1.entity_id1, f1.entity_id2, f2.entity_id1, f2.entity_id2)
) >= 2
希望您没有太多数据。此版本和您尝试的版本都不会在大量数据上有良好的性能。