假设我们有两个表:'Car'和'Part',在'Car_Part'中有一个连接表。说我想看到所有车辆中都有123部分。我能做到这一点:
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))
答案 0 :(得分: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中输出统计信息。然后比较每个查询的统计数据。
如果你不能进行这种类型的测试,那么你可能会面临性能问题,然而你必须调整/纠正这些问题。您可以使用可以为您生成数据的工具。
答案 1 :(得分:3)
我有类似的数据,所以我检查了两种查询样式的执行计划。令我惊讶的是,子查询中的列(CIS)生成了一个执行计划,其I / O成本比内部联接(IJ)查询少25%。在CIS执行计划中,我获得了中间表(Car_Part)的2个索引扫描与中间的索引扫描以及IJ中相对更昂贵的散列连接。我的索引是健康的但非聚集的,因此可以通过聚类来使索引扫描更快一些。我怀疑这会影响散列连接的成本,这是IJ查询中更昂贵的一步。
与其他人指出的一样,这取决于您的数据。如果您在这3张表中使用了许多千兆字节,那么请调整一下。 如果您的行编号为数百或数千,那么您可能会在非常小的性能增益上分裂头发。我会说IJ查询更具可读性,只要它足够好,就行了任何未来的开发人员都会为您的代码提供帮助,并为他们提供更易于阅读的内容。我的表中的行数是188877,283912,13054,并且在更短的时间内返回两个查询以便啜饮咖啡。
小后记:由于你没有聚合任何数值,看起来你的意思是选择不同的。除非你真的要对小组做些什么,否则更容易看到你的意图选择distinct而不是group by。 IO成本是相同的,但一个表明你的意图更好恕我直言。
答案 2 :(得分: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。