2012-08-10 42 views
1
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 

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

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 

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

回答

4

第一个查询有一个或WHERE子句中:

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

第二个查询有效地具有,而是经由所述条件:

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和子查询是否合适。我认为你更想要一个内部连接。可以做更多的工作来改善绩效。

+0

好极了:)谢谢你不会让我给你奖励你11分钟的答案。奖金问题:有没有联接的方式,使其行为相同,并从性能较小的联接中受益? – Wolfe 2012-08-10 21:37:41

+1

在第二个查询的末尾添加'WHERE pb.bike_id IS NOT NULL或vb.bike_id IS NOT NULL'。 – Barmar 2012-08-10 21:42:46

+0

其他连接类型是否也可以工作,例如对这些连接Barmar使用完全连接? – Wolfe 2012-08-10 21:47:56

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值。

有意义吗?

+0

是的,谢谢:) – Wolfe 2012-08-10 22:05:10