Dependent SubQuery v Left Join

时间:2012-07-21 04:12:19

标签: mysql

此查询显示正确的结果,但在执行EXPLAIN时,它会将其列为“Dependent SubQuery”,我认为这很糟糕?

SELECT Competition.CompetitionID, Competition.CompetitionName,     Competition.CompetitionStartDate  
FROM Competition  
WHERE CompetitionID NOT   
IN (  
SELECT CompetitionID  
FROM PicksPoints  
WHERE UserID =1    
)

我尝试将查询更改为:

SELECT Competition.CompetitionID, Competition.CompetitionName,   Competition.CompetitionStartDate  
FROM Competition  
LEFT JOIN PicksPoints ON Competition.CompetitionID = PicksPoints.CompetitionID  
WHERE UserID =1  
and PicksPoints.PicksPointsID is null  

但它显示0行。与实际工作的第一个查询相比,上面有什么问题?

2 个答案:

答案 0 :(得分:1)

秒查询无法生成行:它声称:

WHERE UserID =1  
and PicksPoints.PicksPointsID is null 

但为了澄清,我改写如下:

WHERE PicksPoints.UserID =1  
and PicksPoints.PicksPointsID is null 

因此,一方面,您要求PicksPoints UserId = 1处的行,但是您再次希望该行不存在于第一位。你能看到失败吗?

外部联接非常棘手!通常使用“外部”表中的列进行过滤,例如Competition。但你不希望这样做;你希望过滤左边连接的表。尝试并重写如下:

SELECT Competition.CompetitionID, Competition.CompetitionName,   Competition.CompetitionStartDate  
FROM Competition  
LEFT JOIN PicksPoints ON (Competition.CompetitionID = PicksPoints.CompetitionID AND UserID = 1)
WHERE 
PicksPoints.PicksPointsID is null  

有关详情,请阅读此nice post

但是,作为一个额外的注释,在性能方面,使用子查询或左连接会遇到一些麻烦。

使用子查询会遇到麻烦,因为 5.6 (已完成一些好的工作),MySQL在优化内部查询方面非常糟糕,并且您的子查询预计会执行多次。

使用LEFT JOIN您遇到麻烦,因为LEFT JOIN指示从左到右的加入顺序。然而,您的过滤位于正确的表中,这意味着您将无法使用索引来过滤USerID = 1条件(或者您将失去连接的索引)。

答案 1 :(得分:0)

这是两个不同的查询。第一个查询查找与用户ID 1相关的竞争(通过PicksPoints表),第二个查询与 与用户ID 1相关联的那些行加入,另外还有一个null { {1}}。

第二个查询是空的,因为您要加入一个名为PicksPointsID的表,并且您正在查找连接结果中PicksPoints为空的行。只有在

时才会发生这种情况
  1. 第二个表格中有一行空PicksPointsID 一个竞争ID,与第一个表格中的竞争ID相匹配,或者
  2. 所有第二个表中对连接的贡献中的列为空,因为第一个表中的竞争ID没有出现在第二个表中。
  3. 由于PickPointsID真的听起来像一个主键,所以它出现了案例2。因此PicksPointsID中的所有列都为null,您的where子句(PickPointsID)将始终为false,结果将为空。

    普通的左连接应该适合你

    UserID=1 and PicksPoints.PicksPointsID is null

    select c.CompetitionID, c.CompetitionName, c.CompetitionStartDate from Competition c left join PicksPoints p on (c.CompetitionID = p.CompetitionID) where p.UserID <> 1 替换最终where(制作复杂的连接子句)也可能有效。我将留给您分析每个查询的计划。 :)

    我个人并不认为需要进行and测试。由Shlomi Noach链接的文章非常好,您可以在那里找到一些技巧来帮助您。