Mysql 发现连接(朋友、朋友的朋友)太慢的查询
如果两个用户是朋友,我在“朋友”表中为他们设置了一个条目,如下所示:Mysql 发现连接(朋友、朋友的朋友)太慢的查询,mysql,sql,Mysql,Sql,如果两个用户是朋友,我在“朋友”表中为他们设置了一个条目,如下所示: table: friends ------------------------ uid1 uid2 332 333 现在让我们假设一个新用户(uid=100)加入。我的应用程序找到她附近的用户,然后尝试向她显示他们的连接(fb好友、好友的好友等)。我使用此查询的目的是: SELECT (fr.id IS NOT NULL)+(f2.id
table: friends
------------------------
uid1 uid2
332 333
现在让我们假设一个新用户(uid=100)加入。我的应用程序找到她附近的用户,然后尝试向她显示他们的连接(fb好友、好友的好友等)。我使用此查询的目的是:
SELECT (fr.id IS NOT NULL)+(f2.id IS NOT NULL)*2+(fr.id IS NULL AND f2.id IS NULL)*3 AS connection
FROM users u
LEFT JOIN friends AS fr ON ((fr.uid1='100' AND fr.uid2=u.uid) OR (fr.uid1=u.uid AND fr.uid2='100'))
LEFT JOIN (friends AS f1, friends AS f2) ON fr.id IS NULL AND
(
(f1.uid1='100' AND f1.uid2=f2.uid1 AND f2.uid2=u.uid) OR
(f1.uid2='100' AND f1.uid1=f2.uid1 AND f2.uid2=u.uid) OR
(f1.uid2='100' AND f1.uid1=f2.uid2 AND f2.uid1=u.uid) OR
(f1.uid1='100' AND f1.uid2=f2.uid2 AND f2.uid1=u.uid)
)
WHERE [location near her]
此查询将查找新用户附近的人,对于每个人,“连接”的值将是1(如果与新用户是朋友),2(如果他们有普通朋友),3(否则)
这个查询过去工作正常,但现在我只有多一点用户(10000个),它变得非常慢(只需10秒钟就可以找到新用户附近10个人的连接类型)。
在我的查询或数据库方案中是否存在完全错误的地方?我知道定义索引会使事情变得更快,但我仍然认为这样简单的查询需要10秒的时间是很长的。如果您有任何建议,我将不胜感激。我在sqlfiddle上工作是为了坚持您的问题。 这就是我的建议:
- 不要在
中使用左连接
条件,这是一个性能杀手,最好执行两个或更多连接,而不是使用或
或
- 不要在第二个
左连接
(性能杀手)中使用
,而是在选择部分中使用它:fr.id为NULL
(fr.id不为NULL)+(fr.id为NULL,f2.id不为NULL)*2
- 使用
来显示1/2/3类型的连接(可读性更强)CASE WHEN[cond]然后使用[type_connection]ELSE 3 END
希望有帮助:)你能解释一下这个查询是如何找到人的吗?它只打印一系列数字1,2,3,3,3,2,2,3等等。请看这个演示:这对我来说没有意义。首先,感谢您创建SQLFIDLE。我提到的问题只是一个例子。。实际上,它是(因此它将为每个用户选择与新用户相关的uid和连接类型)您是否可以发布
EXPLAIN select(fr.id不为NULL)的输出?
(即,在查询前面添加一个EXPLAIN
。您在friends表上有一个(uid1,uid2)和一个(uid2,uid1)索引,对吗?
SELECT
u.uid
,CASE
WHEN directFriend.frUid IS NOT NULL THEN 1
WHEN commonFriend.frUid IS NOT NULL THEN 2
ELSE 3
END as connection
FROM
users u
LEFT JOIN(
SELECT
u.uid as frUid
FROM
users u
LEFT JOIN friends as fr1
ON fr1.uid1='1'
AND fr1.uid2=u.uid
LEFT JOIN friends as fr2
ON fr2.uid1=u.uid
AND fr2.uid2='1'
WHERE
fr1.uid2 IS NOT NULL
OR fr2.uid1 IS NOT NULL) as directFriend
ON directFriend.frUid = u.uid
LEFT JOIN(
SELECT
CASE
WHEN common1.uid2 IS NOT NULL THEN common1.uid2
WHEN common2.uid1 IS NOT NULL THEN common2.uid1
END as frUid
FROM
users u
LEFT JOIN friends as fr1
ON fr1.uid1='1'
and fr1.uid2=u.uid
LEFT JOIN friends as fr2
ON fr2.uid2='1'
and fr2.uid1=u.uid
LEFT JOIN friends as common1
ON common1.uid1 = fr1.uid2
AND common1.uid1 = u.uid
LEFT JOIN friends as common2
ON common2.uid2 = fr2.uid1
AND common2.uid2 = u.uid
WHERE
common1.uid2 IS NOT NULL
OR common2.uid1 IS NOT NULL) as commonFriend
ON commonFriend.frUid = u.uid