SQL:join vs where

时间:2014-11-13 19:45:07

标签: sql sql-server postgresql join where

为了简化事情,我的情况是两个表具有一对多(或在某些情况下可能是一对一)关系:例如已完成的帐户和付款,客户和订单等。每个付款/订单只能与1个帐户相关联,但帐户可能有0个,1个或多个与之相关的付款。 如果我想计算每个帐户/客户的付款/订单总数,我会写这样的内容:

Select c.clientid
,coalesce(o.NumOrders,0) as NumOrders

From clients c

Left outer join
( select clientid, count(*) as NumOrders from orders group by clientid ) o
on c.clientid = o.clientid

但是,我也看到过这种类型的编码:

Select c.clientid
, ( select count(orders.clientid) from orders where orders.clientid = c.clientid) as NumOrders

From clients c

您对哪种方法更可取以及为什么有任何意见?

我觉得后者更难阅读,但也许这只是我的习惯。至于性能,如果我没有where子句,似乎第一个更快,但如果我有一个where子句(例如,一个条件只返回220万条记录客户表中的1,000条记录),那么后者似乎更快。

我使用PostgreSQL 9.1和Microsoft SQL Server 2014.谢谢!

3 个答案:

答案 0 :(得分:2)

我更喜欢

Select c.clientid
,count(o.clientid) as NumOrders

From clients c

Left outer join orders o on c.clientid = o.clientid

group by c.clientid

因为它简单明了。

如果我愿意在你的两个版本之间做出选择,我宁愿选择第二个版本,因为它更短(需要阅读和尝试理解的代码更少),但不是特别棘手。第一个必须处理NULL处理,这使得事情变得更加复杂。

答案 1 :(得分:1)

此版本:

Select c.clientid,
       ( select count(o.clientid) from orders o where o.clientid = c.clientid
       ) as NumOrders
From clients c;

有一个主要优势。以下几点解释了它:

select c.*, . . .

也就是说,您可以选择自己喜欢的列,而不必将它们放入group by子句中。提醒一下,您无法将*放入group by

在您的情况下,SQL Server和Postgres具有相当不错的优化器,因此要么应该能够利用索引。并非所有SQL引擎都如此智能。特别是MySQL在第一种情况下使用orders上的索引比在group by情况下更好。

也就是说,第二个版本是标准的SQL代码。

答案 2 :(得分:1)

左派连接到派生表而不是select子句中的相关子查询通常会更有效。相关子查询强制循环子查询,而左连接可以使用循环或散列连接。您确实希望在示例中包含该组,就像您在示例中一样,因为它可以使用外键上的索引来计算聚合,而仅对简单的左连接进行分组则不会。如果你有一个where子句,它取决于它过滤哪个表。如果要对orders表进行过滤,请确保在派生表中包含where子句。如果您使用where子句显着地减少了clients表中的行数,那么是的,像第二个示例那样的相关子查询只会执行一些循环子查询,而不是尝试计算整个聚合总计表,可能是数百万的订单。但是,我建议在该实例中使用外部apply来在join子句中而不是在select子句中执行相关子查询,因为如果需要,它将允许您访问表中的其他列,并且没有真正的缺点。所以我一般会推荐你的第一个例子:

Select c.clientid
,coalesce(o.NumOrders,0) as NumOrders

From clients c

Left outer join
( select clientid, count(*) as NumOrders from orders group by clientid ) o
on c.clientid = o.clientid