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
  • 使用
    CASE WHEN[cond]然后使用[type_connection]ELSE 3 END
    来显示1/2/3类型的连接(可读性更强)
下面是我建议的代码(例如:uid=1的新用户):


希望有帮助:)

你能解释一下这个查询是如何找到人的吗?它只打印一系列数字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