2010-07-01 85 views
9

假设我们有两个表格:'Car'和'Part',并在'Car_Part'中加入一个表格。假设我想查看其中有123部分的所有汽车。我可以这样做:哪一个更快:加入GROUP BY或子查询?

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
WHERE Car_Part.Part_Id = @part_to_look_for 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

或者我能做到这一点

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE Car.Car_Id IN (SELECT Car_Id FROM Car_Part WHERE Part_Id = @part_to_look_for) 

现在,一切都在我想用第一种方法,因为我一直好父母谁在我灌输长大清教徒对子查询的憎恨和对集合论的热爱,但是有人向我建议,做这么大的GROUP BY比子查询更糟糕。

我应该指出,我们在SQL Server 2008上。我也应该说,实际上我想根据零件ID,零件类型和其他可能的情况来选择。所以,我想真正做的查询看起来是这样的:

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
WHERE (@part_Id IS NULL OR Car_Part.Part_Id = @part_Id) 
AND (@part_type IS NULL OR Part.Part_Type = @part_type) 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

或者......

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE (@part_Id IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    WHERE Part_Id = @part_Id)) 
AND (@part_type IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
    WHERE Part.Part_Type = @part_type)) 
+2

你跑了吗?看着查询计划?基准? – Oded 2010-07-01 08:27:58

+1

我不得不生成大量的数据,所以我不会在下个星期之前了解它。当我搜索答案时,我没有找到答案,所以值得在网上发布一个可能正在寻找的人的问题。 – d4nt 2010-07-01 08:31:00

+0

Group By是劳动密集型的,用于计算像平均数,总和等东西。您似乎使用它来消除重复项。尝试DISTINCT没有群组... – Alocyte 2017-11-23 14:14:27

回答

3

我有类似的数据,所以我检查了这两种查询风格的执行计划。令我惊讶的是,在子查询中的列(CIS)产生了一个执行计划,比内部连接(IJ)查询少25%的I/O开销。在CIS执行计划中,我得到了中间表(Car_Part)的2个索引扫描与中间索引扫描,以及IJ中相对更昂贵的散列连接。我的索引是健康的,但是非聚集的,所以有理由认为索引扫描可能会通过聚集它们而变得更快一些。我怀疑这会影响散列连接的成本,这是IJ查询中更昂贵的步骤。

像其他人一样指出,这取决于您的数据。如果你在这3个表中使用了很多千兆字节,然后调离。 如果你的行数以数百或数千计数,那么你可能会以非常小的性能增益分割毛发。我会说IJ查询的可读性要好得多,只要它足够好,可以做任何未来的开发人员,他们会帮助您更好地阅读代码并为其提供便利。我的表中的行数是188877,283912,13054,并且两个查询都返回的时间更短,以至于只能喝咖啡。

小postscript:因为你不汇总任何数值,它看起来像你的意思是选择不同。除非你真的要对这个小组做些什么,否则最后你会更容易看到你的意图是选择不同的而不是小组。IO成本是相同的,但一个表明你的意图更好恕我直言。

4

你能做的最好的事情是自己进行测试,在现实的数据量。这不仅有利于这个查询,而且对于所有未来的查询,当你不确定哪个是最好的方法时。

重要的事情要做包括:
- 生产级数据量的测试
- 测试相当&一致(清除缓存:http://www.adathedev.co.uk/2010/02/would-you-like-sql-cache-with-that.html
- 你既可以使用SQL事件探查监控检查执行计划

并检查持续时间/读取/写入/ CPU,或SET STATISTICS IO ON; SET STATISTICS TIME ON;在SSMS中输出统计信息。然后比较每个查询的统计信息。

如果你不能做这种类型的测试,你可能会暴露自己的性能问题,你必须调整/纠正。你可以使用那些可以为你生成数据的工具。

2

有了SQL Server 2008我希望In要快,因为它等同于这一点。

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE EXISTS(SELECT * FROM Car_Part 
      WHERE Car_Part.Car_Id = Car.Car_Id 
      AND Car_Part.Part_Id = @part_to_look_for 
) 

即它只需要检查行的存在不加入它然后删除重复。这是discussed here