子查询的可伸缩性和可能的​​替代方案

时间:2013-03-05 01:03:13

标签: mysql sql subquery

前面有两件事。首先,我有一个解决我的问题的方法。我在这里是为了指导它是否是一个好的解决方案,如果我能做得更好。其次,我想为前方的无知道歉!我是一个java人,正在建立一个刚刚进入SQL的网站。我还有很多学习要做的事情,这就是为什么我在这里寻找指导。

我有三个表来处理这个查询。

  1. 用户 - 有关网站上所有用户的基本信息
  2. 朋友 - 持有两个朋友的用户ID
  3. 大踏步 - 想想像facebook墙上的帖子一样的步伐。任何用户都可以在他们的墙上或朋友的墙上发布步幅更新。
  4. 用于查找所有用户朋友并返回其ID号的SQL语句如下所示。

    SELECT user.id 
    FROM user 
    INNER JOIN friends ON user.id = friends.user2 WHERE friends.user1 = 1 
    UNION ALL 
    SELECT user.id FROM user 
    INNER JOIN friends on user.id = friends.user1 WHERE friends.user2 = 1
    

    现在我的目标是让Facebook像实时Feed一样。因此,每当用户发布步幅时,他们的所有朋友都会被通知。所以我知道第一步是让所有用户朋友,我在上面这样做了。所以现在我想将这些朋友链接到步幅表。

    在步幅表中有sourceUserId(编写步幅的人)和recipientId(收到步幅的人)的列。因此,如果您在自己的电路板上写字并且您的ID是2,那么两列都是2。我的目标是创建一个SQL语句,可以找到所有用户朋友,以及这些朋友在他们的董事会和朋友板上发布的所有帖子。

    经过太多的谷歌搜索后,我发现了SQL子查询,并得出了结果。问题是我是新手,不知道这是否是一个好结果,因为我今天才了解这些事情!我害怕可扩展性,如果有100,1000甚至100,000用户,这件事情就会变得混乱!所以我的问题是,

    1. 子查询是最好的选择吗?如果是这样,我做得对吗?如果没有,我该如何解决这个问题
    2. 是否有任何列我应该编制索引以加快此查询。
    3. 关于如何改进我未来的查询,您对新的SQL人员有任何其他建议吗
    4. 这是我提出的代码!

      SELECT * FROM stride WHERE sourceUserId = ANY
      (
          SELECT user.id 
          FROM user 
          INNER JOIN friends ON user.id = friends.user2 WHERE friends.user1 = 1 
          UNION ALL 
          SELECT user.id FROM user 
          INNER JOIN friends on user.id = friends.user1 WHERE friends.user2 = 1
      ) 
      AND recipientId = ANY
      (
          SELECT user.id 
          FROM user 
          INNER JOIN friends ON user.id = friends.user2 WHERE friends.user1 = 1 
          UNION ALL 
          SELECT user.id FROM user 
          INNER JOIN friends on user.id = friends.user1 WHERE friends.user2 = 1
      ) 
      

      更新:凭借一堆新知识,我能够为我的实时Feed获得0.0009秒的可靠SQL语句!这是任何有兴趣的人。

      SELECT stride.id AS link, sourceUser.userName, sourceUser.displayName, recipientUser.fName AS recipient, sourceUser.currentDefault, stride.content, stride.timestamp,
      
      CASE WHEN (recipientId = sourceUserId) THEN "personalStride" ELSE "friendStride" END AS notType
      FROM stride
      
      INNER JOIN user AS sourceUser ON sourceUser.id = stride.sourceUserId
      INNER JOIN user AS recipientUser ON recipientUser.id = stride.recipientId
      
      WHERE sourceUserId = ANY
      (
          SELECT CASE WHEN user1 = 1 
          THEN user2 ELSE user1 END AS sourceUserId
          FROM friends
          WHERE user1 = 1 OR user2 = 1
      ) 
      AND recipientId = ANY
      (
          SELECT CASE WHEN user1 = 1 
          THEN user2 ELSE user1 END AS sourceUserId
          FROM friends
          WHERE user1 = 1 OR user2 = 1
      )
      ORDER BY timestamp desc
      

1 个答案:

答案 0 :(得分:0)

您不需要工会:

SELECT 
    CASE
        WHEN f.user1=u.id 
        THEN f.user2 
        ELSE f.user1 
    END AS f_id 
FROM user 
   JOIN friends AS f 
        ON f.user1=u.id OR f.user2=u.id
WHERE u.id = 1

实际上你也不需要和用户一起加入(当然假设在friends表中的每个id都在users表中有匹配),我只是添加了它,所以我们可以拥有漂亮的“u.id”而不是幻数

SELECT 
    CASE 
        WHEN f.user1=2 
        THEN f.user2 
        ELSE f.user1 
    END AS f_id 
FROM friends AS f 
WHERE f.user1=2 OR f.user2=2

http://sqlfiddle.com/#!2/afb4d/8

修改 至于另一个查询,问题有点复杂,我最终得到了这样的查询:

SELECT s.id,s.sourceUserId,s.recipientId
FROM STRIDE as s 
    JOIN  friends AS f 
        ON 
          (
            ((s.sourceUserId=f.user1 OR s.recipientId=f.user1) AND f.user2=1) OR
            ((s.sourceUserId=f.user2  OR s.recipientId=f.user2)AND f.user1=1)
          )
GROUP BY s.id,s.sourceUserId,s.recipientId
HAVING COUNT(*)=2 OR s.sourceUserId=s.recipientId;

http://sqlfiddle.com/#!2/83363/1 如果源或收件人是我们用户的朋友,我们选择该行,我们总结一下,如果该行显示两次,则表示源和收件人都是朋友。我们还会选择source = recipient的那些,因为它们只会出现一次。

子查询很有用,但除非你需要两个不同的聚合,否则它们是可以避免的,并且通常避免它们会更快。