11

我有两个包含任务和注释的表,并且想要检索任务列表以及每个任务的关联注释数。这两个查询完成了这项工作:

选择 t.TaskId,
       (select count(n.TaskNoteId) from TaskNote n where n.TaskId = t.TaskId) 'Notes'
从任务 t

-  或者
选择 t.TaskId,
       count(n.TaskNoteId) '笔记'
从任务 t
左连接
       任务说明 n
在 t.TaskId = n.TaskId
按 t.TaskId 分组

它们之间有区别吗?我应该使用另一种,还是它们只是做同一工作的两种方式?谢谢。

4

7 回答 7

12

在小型数据集上,它们在性能方面被淘汰了。编入索引后,LOJ 会好一些。

我在大型数据集上发现内部联接(内部联接也可以工作。)将在一个非常大的因素上胜过子查询(对不起,没有数字)。

于 2008-09-22T22:29:13.557 回答
6

在大多数情况下,优化器会对它们一视同仁。

我更喜欢第二种,因为它的嵌套更少,这使得它更容易阅读和维护。出于同样的原因,我也开始使用 SQL Server 的公用表表达式来减少嵌套。

此外,如果将来除了 COUNT 之外还可能添加更多聚合,例如 MIN(some_scalar)、MAX()、AVG() 等,则第二种语法更加灵活。

于 2008-09-22T22:29:47.657 回答
5

子查询会更慢,因为它正在为外部查询中的每一行执行。加入会更快,因为它只完成一次。我相信查询优化器不会重写这个查询计划,因为它无法识别等价。

通常,您会为这种计数进行加入和分组。如果它们必须对未参与另一个连接的表进行一些分组或更复杂的谓词,则您显示的那种相关子查询主要是令人感兴趣的。

于 2008-09-24T15:54:00.853 回答
2

如果您使用的是 SQL Server Management Studio,则可以将这两个版本都输入到查询编辑器中,然后右键单击并选择显示估计的执行计划。它会给你相对于批次的两个百分比的成本。如果预计它们花费相同的时间,它们都将显示为 50% - 在这种情况下,出于其他原因(更易于阅读、更易于维护、更符合您的编码标准等)选择您喜欢的任何一个。否则,您可以选择相对于批次成本百分比较低的那个。

您可以使用相同的技术来查看更改任何查询以通过比较执行相同操作的两个版本来提高性能。

当然,因为它是相对于批次的成本,这并不意味着任何一个查询都尽可能快 - 它只是告诉您它们如何相互比较,而不是一些名义上的最佳查询以获得相同的结果.

于 2008-09-22T22:46:23.063 回答
1

对此没有明确的答案。您应该查看 SQL 计划。在关系代数方面,它们本质上是等价的。

于 2008-09-22T22:23:21.247 回答
1

我强调尽可能避免子查询。连接通常会更有效。

于 2008-09-25T18:26:06.377 回答
0

您可以使用其中任何一个,它们在语义上是相同的。一般来说,经验法则是使用更容易阅读的形式,除非性能是一个问题。

如果性能是一个问题,那么尝试使用其他形式重写查询。有时优化器会为一种形式使用索引,而不是另一种。

于 2008-09-22T22:20:33.703 回答