【问题标题】:SQL: Using COUNT(*) Instead of EXISTSSQL:使用 COUNT(*) 而不是 EXISTS
【发布时间】:2013-08-05 16:06:19
【问题描述】:

是否可以使用 COUNT 代替 EXISTS?

我有以下查询:

SELECT * 
FROM Goals G
WHERE EXISTS (SELECT NULL FROM tfv_home_last6(G.Date, G.Home) WHERE GameNumber <= 6 AND     
HomeGoals >= 3)

如果子查询中至少存在一行,而不是返回该行,我想指定需要在子查询中返回的行数,例如

SELECT * 
FROM Goals G
WHERE ROWCOUNT(*) >= 2 (SELECT NULL FROM tfv_home_last6(G.Date, G.Home) WHERE GameNumber <= 6 AND     
HomeGoals >= 3)

我不知道该怎么做?

我使用的是 SQL Server 2012。

【问题讨论】:

  • 这是可能 - 但不是推荐 - 为什么?想象一个有 1000 万行的表;如果您使用COUNT(*) &gt; 0,则查询必须运行在整个1000 万行 以计算您的值的出现次数并返回该计数。另一方面,如果您使用IF EXISTS(),则只要第一次出现,查询就会停止。所以是的 - 你可以但你不应该
  • @marc_s - 这是一个很好的警告,但它可能仍然是最佳选择。
  • @Greg:绝对不是在一张大桌子上! (> 100 万行)
  • @marc_s - OP 没有提到一张大桌子,这就是为什么我说这是一个警告。
  • @YK:如果您有一个支持子查询的WHEREORDER BY 子句的良好索引,并且您没有选择TOP (9999999) .... - 那么是的,这可能会起作用。使用索引和足够小的数字,您将只获得该数量的行

标签: sql sql-server-2012


【解决方案1】:

您可以像您描述的那样执行子查询:

SELECT * 
FROM Goals G
WHERE (SELECT count(*)
       FROM tfv_home_last6(G.Date, G.Home)
       WHERE GameNumber <= 6 AND HomeGoals >= 3
      ) > 0;

但是,这需要计算整个计数。 exists 表单效率更高,因为它在第一个匹配记录处停止。

在 SQL Server 2012 中,您还可以使用 `cross apply:

SELECT * 
FROM Goals G cross apply
     (select count(*) as cnt
      FROM tfv_home_last6(G.Date, G.Home)
      WHERE GameNumber <= 6 AND HomeGoals >= 3
     ) a
WHERE a.cnt > 0;

我不知道哪个会有更好的性能,where 子句中的相关子查询或 交叉应用版本。

【讨论】:

  • 如果子查询在where 子句中,它不会为每一行运行吗?与您的 from 子句中只运行一次的子查询相比?
  • @JafarKofahi 。 . .嗯,是。它是一个相关的子查询,因此它必须为每一行运行,才能获得正确的行。 cross apply 会做同样的事情。不要混淆运行子查询和对所有数据运行子查询。在这两种情况下,它将使用Goals 的一行中的值运行子查询。
  • 当它在WHERE 子句中时,它会为每一行单独运行子查询(如存储过程),还是优化器基本上将其转换为JOIN
  • @ Gordon Linoff - 这已经成功了,谢谢。我都试过了,性能似乎没有区别,所以我选择第一个。
猜你喜欢
  • 1970-01-01
  • 2016-04-17
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 2011-07-12
  • 2021-10-22
相关资源
最近更新 更多