【问题标题】:Select * from table1 that does not exist in table2 with conditionalselect * from table1 that does not exist in table2 with conditional
【发布时间】:2009-10-21 01:42:35
【问题描述】:

我有 2 张桌子。一个是一张桌子,上面有可以学习的东西。有一个描述每种行的 JID,并且对每一行都是唯一的。第二个表是学习过的东西的日志(JID)以及学习它的人的用户 ID。我目前正在使用它来选择 JID 的所有数据,但只选择用户根据 userid 学习的数据。

SELECT * 
FROM tablelist1
LEFT JOIN tablelog2 ON (tablelist1.JID = tablelog2.JID) 
                       AND tablelog2.UID = 'php var'
WHERE tablelog2.JID IS NOT NULL

我现在需要选择要学习的内容行,但只选择用户 ID 尚未学习的内容。我显然对此很陌生,请耐心等待。 :) 我尝试使用 IS NULL,但虽然它似乎有效,但它给出了重复的 JID,一个是 NULL,一个是正确的。

【问题讨论】:

    标签: sql mysql


    【解决方案1】:

    使用 LEFT JOIN/IS NULL:

       SELECT t.*
         FROM TABLE_LIST t
    LEFT JOIN TABLE_LOG tl ON tl.jid = t.jid
        WHERE tl.jid IS NULL
    

    使用 NOT IN:

    SELECT t.*
      FROM TABLE_LIST t
     WHERE t.jid NOT IN (SELECT tl.jid
                           FROM TABLE_LOG tl
                       GROUP BY tl.jid)
    

    使用不存在:

    SELECT t.*
      FROM TABLE_LIST t
     WHERE NOT EXISTS(SELECT NULL
                        FROM TABLE_LOG tl
                       WHERE tl.jid = t.jid)
    

    仅供参考
    LEFT JOIN/IS NULL 和 NOT IN 在 MySQL 中是等价的 - 它们执行相同,而 NOT EXISTS 更慢/效率更低。更多详情:http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/

    【讨论】:

    • 是否可以不使用子查询?子查询非常慢,表 2 将有很多行。与我最初使用连接的方式相同。
    • 左连接工作完美。感谢您的仅供参考。我不知道 NOT IN 是相等的,尽管看起来额外的选择会减慢它的速度!
    【解决方案2】:

    首先,您应该在现有查询上使用 INNER JOIN:

    SELECT * FROM tablelist1
        INNER JOIN tablelog2 ON (tablelist1.JID = tablelog2.JID) 
        WHERE tablelog2.UID = 'php var'
    

    你这样做的方式是从 tablelist1 中获取所有行,然后会额外麻烦排除在 tablelog2 中没有匹配的行。 INNER JOIN 将为您做到这一点,而且效率更高。

    其次,要为用户“X”查找用户尚未学习的所有可学习内容,请执行以下操作:

    SELECT * FROM tablelist1 
        WHERE NOT EXISTS (SELECT JID FROM tablelog2 WHERE UID = 'X')
    

    【讨论】:

    • 我将测试第一个建议。第二个(不存在)更容易,但速度较慢,这是我想避免的,因为 t2log 可能有很多记录。
    • 第二条命令的执行时间主要取决于tablelist1的大小和tablelog2中匹配UID = 'X'的记录数。请注意,子查询与查询的主要部分不相关,只需运行一次,并且如果存在 UID、JID 的覆盖索引,则它很容易被覆盖索引处理。
    • PS:你的意思是你知道第二个命令太慢,还是你认为这是因为你在某处阅读以避免这种结构?先测试一下,除非 UID "X" 的学习内容非常多,否则应该很快。
    • table2 预计大约有 1m 行,可能有超过 200k 的用户。因此,虽然现在这不是问题,但我想确保现在牢记这一点。每个毫秒对我来说都很重要。但我会加上你的答案,因为它很有帮助。
    • 看,从您在问题中发布的 SQL 来看,很明显,正如您所说,您在这方面非常非常新。为什么要发布一个问题,然后与试图帮助你的人争论呢? 200K 用户和 1M 记录是每个用户只有 5 条记录,取自覆盖索引,并且在 tablelist 中检查的行中只执行一次。您几乎肯定是在发明一个根本不存在的性能瓶颈。
    猜你喜欢
    • 1970-01-01
    • 2017-11-15
    • 2014-06-17
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    相关资源
    最近更新 更多