建议SQL查询

时间:2016-05-16 18:36:13

标签: php mysql sql

基本上我要做的是根据共同的兴趣来建议人。

我有一个用户表。

我有一个Interested_People表,其中存储了UserID + InterestID。

我有一个联系人列表,其中存储了彼此相加的人。

我想要的只是输出不是你朋友的人。

我在互联网上搜索了很多但却找不到这样的东西。

虽然我创建了一个查询,但速度非常慢。现在我请求你们,如果你可以稍微编辑我的查询,并使其更多带宽&时间有效。

SELECT * 
FROM   users 
WHERE  id IN(SELECT userid 
             FROM   interested_people 
             WHERE  interested_in IN(SELECT interested_in 
                                     FROM   interested_people 
                                     WHERE  userid = [userid]) 
                    AND id NOT IN(SELECT user1 AS my_friends_userid 
                                  FROM   contactlist f 
                                  WHERE  f.user2 = [userid] 
                                    AND accepted = 1 
                                  UNION 
                                  SELECT user2 AS my_friends_userid 
                                  FROM   contactlist f 
                                  WHERE  f.user1 = [userid] 
                                    AND accepted = 1)) 
       AND id != [userid] 
ORDER  BY Rand () 
LIMIT  0, 10; 

此查询实际上完成了这项工作,但在本地计算机中需要很长时间约16秒。那不是我想要的。我想要一个快速可靠的人。

提前致谢!

3 个答案:

答案 0 :(得分:1)

WHERE子句中的子查询在MySQL中通常很慢;至少比可比的JOIN慢。

SELECT others.*
FROM interested_people AS userI
INNER JOIN interested_people AS othersI 
   ON userI.interestid = othersI.interestid 
   AND userI.userid <> othersI.userid
INNER JOIN users AS others ON othersI.user_id = others.userid
LEFT JOIN contactlist AS cl 
   ON userI.userid = cl.user1 
   AND others.userid = cl.user2
   AND cl.accepted = 1
WHERE userI.userid = [userid] 
   AND cl.accepted IS NULL
ORDER BY RAND()
LIMIT 0, 10;

注意:直觉让我想知道联系人列表可能更好地作为where子查询。

AND cl.accepted IS NULL最终在JOIN之后处理,导致只允许在联系人列表中没有匹配的结果。

如果你想进一步提升一点:

SELECT others.*, COUNT(1) AS interestsCount
...
GROUP BY others.userid
ORDER BY interestsCount DESC, RAND()
LIMIT 0,10;

这会让您随机选择最有共同兴趣的人。

答案 1 :(得分:1)

首先,查看您感兴趣的查询并假设“userID” 你正在测试is = 1.听起来你正试图获得一个级别 远离那些用户1也对...感兴趣。

SELECT userid FROM interested_people 
   WHERE interested_in IN 
         ( SELECT interested_in FROM interested_people 
              WHERE userid = [userid] ) 

Interested_People的示例数据

userID  Interested_In
1        5
1        7
1        8
2        3
2        5
2        7
7        1
7        2
7        5
8        3

在这种情况下,最内层返回interest_in值为5,7,8。 然后,让所有对5,7和8感兴趣的用户返回2和7。 (但由于用户2和7都对5感兴趣,因此2 ID将返回TWICE 因此可能会在以后重复加入。我会做的很明显。这都儿一样 结果可以使用以下查询完成,您可以使用...

进行采样
SELECT distinct ip2.userid
   from
      interested_people ip
         join interested_people ip2
            ON ip.interested_in = ip2.interested_in
   where
      userid = [parmUserID]

现在,您需要从此列表中排除已接受的所有联系人。 然后,您可以左键连接两次以进行联系,并确保为NULL 表示没有其中一个联系人...然后再次加入到用户表中 获取用户详细信息。

SELECT
      u.*
   from
      users u
         JOIN 
         ( SELECT distinct 
                 ip2.userid
              from
                 interested_people ip
                    join interested_people ip2
                       ON ip.interested_in = ip2.interested_in
                       left join contactList cl1
                          ON ip2.userid = cl1.user1
                          AND cl1.accepted = 1
                       left join contactList cl2
                          ON ip2.userid = cl2.user2
                          AND cl2.accepted = 1
              where
                 ip.userid = [parmUserID]
                 AND NOT ip2.userID = [parmUserID] ) PreQuery
         ON u.id = PreQuery.userID
   order by
      RAND()
   limit
      0, 10

我会在你的contactList表上有两个索引来优化左连接... user1和user2在主要位置......同样对于interested_people表。

table             index
contactList       ( user1, accepted )
contactList       ( user2, accepted )
interested_people ( userid, interested_in )
interested_people ( interested_in, userid )

我希望您的用户表已经在ID上作为主键索引。

答案 2 :(得分:0)

我认为这会给你相同的结果,但表现更好:

SELECT * FROM Users u
    INNER JOIN interested_people i
    ON u.id = i.userid
WHERE NOT EXISTS
    (SELECT * FROM contacts WHERE user1 = [userid] or user2 = [userid] and accepted=1)
AND id != [userid]
ORDER BY Rand()
LIMIT 0, 10

如果合理,请跳过ORDER BY子句。那将是最昂贵的部分

select和join子句为您提供了对连接感兴趣的用户,而WHERE NOT EXISTS是一种高效的方法来排除已列出的联系人。