为什么这两个mysql查询不同?

时间:2012-08-10 21:33:02

标签: mysql

select distinct p.product_id from cscart_products p 
    left join product_bikes pb on p.product_id = pb.product_id
    left join cscart_product_options po on po.product_id = p.product_id
    left join cscart_product_option_variants pov on pov.option_id = po.option_id
    left join variant_bikes vb on vb.variant_id = pov.variant_id
    where pb.bike_id = 111 or vb.bike_id = 111 

select distinct p.product_id from cscart_products p 
    left join product_bikes pb on p.product_id = pb.product_id and pb.bike_id = 111
    left join cscart_product_options po on po.product_id = p.product_id
    left join cscart_product_option_variants pov on pov.option_id = po.option_id
    left join variant_bikes vb on vb.variant_id = pov.variant_id and vb.bike_id = 111

返回不同的结果集,为什么?

2 个答案:

答案 0 :(得分:4)

第一个查询在WHERE子句中有一个OR:

WHERE pb.bike_id = 111 OR vb.bike_id = 111

第二个查询通过以下条件有效地使用AND:

LEFT JOIN product_bikes pb ON p.product_id = pb.product_id AND pb.bike_id = 111
...
LEFT JOIN variant_bikes vb ON vb.variant_id = pov.variant_id AND vb.bike_id = 111

  

奖金问题:是否有一种方法可以使连接使其行为相同并从性能较小的连接中获益?

有一种方法可以编写查询,但它不一定更快,因为该方法(我在想)使用UNION:

select distinct p.product_id from cscart_products p 
    left join product_bikes pb on p.product_id = pb.product_id and pb.bike_id = 111
    left join cscart_product_options po on po.product_id = p.product_id
    left join cscart_product_option_variants pov on pov.option_id = po.option_id
    left join variant_bikes vb on vb.variant_id = pov.variant_id -- and vb.bike_id = 111
UNION
select distinct p.product_id from cscart_products p 
    left join product_bikes pb on p.product_id = pb.product_id -- and pb.bike_id = 111
    left join cscart_product_options po on po.product_id = p.product_id
    left join cscart_product_option_variants pov on pov.option_id = po.option_id
    left join variant_bikes vb on vb.variant_id = pov.variant_id and vb.bike_id = 111

可能有一种更好的方法,例如你有一个UNION子查询:

SELECT DISTINCT p.product_id
  FROM      cscart_products                AS p 
  LEFT JOIN cscart_product_options         AS po  ON po.product_id = p.product_id
  LEFT JOIN cscart_product_option_variants AS pov ON pov.option_id = po.option_id
  LEFT JOIN (SELECT vb.product_id FROM variant_bikes AS vb WHERE vb.bike_id = 111
             UNION
             SELECT pb.product_id FROM product_bikes AS pb WHERE pb.bike_id = 111
            ) AS pv ON pv.product_id = p.product_id

由于您(在此示例中)不是从cscart_product_optionscscart_product_options_variants表中选择数据,因此您可以从查询中删除这些数据。您还应该查看带有子查询的LEFT JOIN是否合适;我认为你更想要一个内部联接。可能会有更多工作可以改善绩效。

答案 1 :(得分:1)

除了乔纳森所说的。在第一个查询中,WHERE强制它没有得到任何结果,除非(pb.bike_id = 111或vb.bike_id = 111)为真。在第二个查询中,即使只有一行可以通过LEFT JOIN加入,您将获得所有DISTINCT [product_id]。

如果您从第二个查询到第一个查询获得了大量结果,那就是这样。更简单的方法是在SELECT中加入更多内容:

SELECT p.product_id, pb.bike_id ...

如果你这样做,你会注意到第一个查询在它显示的每个产品中都有111个,但是第二个查询将为pb.bike_id提供很多NULL值。

有意义吗?