Count(*)vs Count(1) - SQL Server

sup*_*er9 699 sql sql-server performance

只是想知道你们中的任何一个人是否Count(1)过度使用过Count(*),如果性能有显着差异,或者这只是从过去几天带来的遗留习惯?

(具体数据库是SQL Server 2005.)

gbn*_*gbn 576

没有区别.

原因:

网上书籍说" COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )"

"1"是一个非空表达式:所以它与...相同COUNT(*).优化器会识别它的含义:琐碎.

EXISTS (SELECT * ...或相同EXISTS (SELECT 1 ...

例:

SELECT COUNT(1) FROM dbo.tab800krows
SELECT COUNT(1),FKID FROM dbo.tab800krows GROUP BY FKID

SELECT COUNT(*) FROM dbo.tab800krows
SELECT COUNT(*),FKID FROM dbo.tab800krows GROUP BY FKID
Run Code Online (Sandbox Code Playgroud)

相同的IO,同样的计划,工程

编辑,2011年8月

关于DBA.SE的类似问题.

编辑,2011年12月

COUNT(*)ANSI-92中特别提到(寻找" Scalar expressions 125")

案件:

a)如果指定COUNT(*),则结果是T的基数.

也就是说,ANSI标准认为它明显是你的意思.由于这种迷信COUNT(1),RDBMS供应商已对其进行了优化.否则,它将按照ANSI进行评估

b)否则,让TX成为单列表,它是将<value expression>应用于T的每一行并消除空值的结果.如果消除了一个或多个空值,则会引发完成条件:警告 -


Qua*_*noi 70

在SQL Server中,这些语句产生相同的计划.

与流行的观点相反,在Oracle中他们也这样做.

SYS_GUID() 在Oracle中是相当计算密集的功能.

在我的测试数据库中,t_even是一个包含1,000,000行的表

这个查询:

SELECT  COUNT(SYS_GUID())
FROM    t_even
Run Code Online (Sandbox Code Playgroud)

运行48几秒钟,因为函数需要评估每个SYS_GUID()返回以确保它不是一个NULL.

但是,这个查询:

SELECT  COUNT(*)
FROM    (
        SELECT  SYS_GUID()
        FROM    t_even
        )
Run Code Online (Sandbox Code Playgroud)

只运行了2几秒钟,因为它甚至没有尝试评估SYS_GUID()(尽管*是参数COUNT(*))

  • @asgs:假设您知道“map”方法的作用,您是否看到这两个表达式:“t_even.map(() =&gt; sys_guid()).length”和“t_even.length”总是返回相同的结果价值?Oracle 的优化器足够聪明,可以看到它并优化“map”部分。 (2认同)

Ton*_*ews 63

显然,COUNT(*)和COUNT(1)将始终返回相同的结果.因此,如果一个比另一个慢,那实际上是由于一个优化器错误.由于这两种形式在查询中经常使用,因此DBMS允许这样的错误保持不固定是没有意义的.因此,您会发现两种形式的性能在所有主要的SQL DBMS中(可能)相同.

  • 如果 count(1) 比 count(\*) 慢,我不会认为这是一个错误。如果您要求 dbms 生成 1 并计算不为空的那些,那么是的,它归结为记录计数,但您不能指望 dbms 检测到您编写的每一个废话并为您规避它。 (4认同)
  • 好吧,优化器是为了优化,对于一个计数,只需要考虑两种情况:可能为空的表达式,永远不会为空的表达式:count(1) 属于后者,因此 DBMS 不需要“生成” 1 来回答问题。(顺便说一句,出于审美原因,除了 count(*) 之外,我永远不会使用任何东西。) (3认同)

one*_*hen 20

在SQL-92标准中,COUNT(*)具体表示"表表达式的基数"(可以是基表,`VIEW,派生表,CTE等).

我想这个想法很COUNT(*)容易解析.使用任何其他表达式都需要解析器确保它不引用任何列(COUNT('a')其中a是文字,COUNT(a)哪个a列可以产生不同的结果).

同样,COUNT(*)熟悉SQL标准的人类编码人员可以轻松挑选出来,这是使用多个供应商的SQL产品时的一项有用技能.

此外,在特殊情况下SELECT COUNT(*) FROM MyPersistedTable;,思考是DBMS可能会保存表的基数的统计信息.

因此,因为COUNT(1)并且COUNT(*)在语义上等同,我使用COUNT(*).


Con*_*SFT 19

我在SQL Server团队中工作,我希望可以澄清此线程中的几点(我以前没有看到过,所以对不起工程团队以前没有这样做)。

首先,select count(1) from tablevs与之间没有语义差异select count(*) from table。在所有情况下,它们都返回相同的结果(如果不是,则为错误)。如其他答案所述,select count(column) from table在语义上是不同的,并不总是返回与相同的结果count(*)

其次,关于性能,在SQL Server(和SQL Azure)中有两个方面很重要:编译时工作和执行时工作。在当前实现中,编译时间工作是很少的额外工作。在某些情况下,*会扩展到所有列,然后由于某些内部操作在绑定和优化中的工作方式,导致输出减少到1列。我怀疑它是否会出现在任何可衡量的测试中,并且很可能会被掩盖下发生的所有其他事情(例如自动状态,xevent会话,查询存储开销,触发器等)所干扰。这可能是数千条额外的CPU指令。所以,count(1)在编译期间的工作量要少一些(通常只发生一次,并且计划在多个后续执行中进行缓存)。对于执行时间,假设计划相同,则不应有可测量的差异。(较早的示例之一显示出差异-如果计划相同,则很可能是由于计算机上的其他因素引起的)。

关于计划可能如何有所不同。这些是极不可能发生的,但在当前优化器的体系结构中有可能实现。SQL Server的优化器用作搜索程序(请考虑:计算机程序下棋,通过各种替代方法搜索查询的不同部分,并计算替代方法以在合理的时间内找到最便宜的计划)。该搜索在如何保持查询编译在合理的时间内完成方面有一些限制。对于最琐碎的查询,存在搜索的各个阶段,它们根据优化器认为查询可能执行的成本来处理查询。有3个主要搜索阶段,每个阶段都可以运行更具进取性(昂贵)的启发式尝试,以寻找比任何现有解决方案都便宜的计划。最终,每个阶段的末尾都有一个决策过程,试图确定是应该返回到目前为止找到的计划还是应该继续搜索。此过程使用了到目前为止所花费的总时间与迄今为止找到的最佳计划的估计成本。因此,在具有不同CPU速度的不同机器上,有可能(尽管很少)获得不同的计划,这是因为在较早的阶段通过计划超时而继续进行下一个搜索阶段。还有一些类似的场景与超时有关,可能会在非常非常昂贵的查询上耗尽内存,这些查询消耗了计算机上的所有内存(通常不会在64位上出现问题,但这是一个更大的问题返回32位服务器)。最终,如果您获得了不同的计划,则运行时的性能将有所不同。我不

网络:请使用您想要的两者中的任何一个,因为任何实际形式都无关紧要。(老实说,有很多影响SQL性能的因素远远超出了本主题)。

我希望这有帮助。我确实写了一本书关于优化器如何工作的章节,但是我不知道是否适合将其发布在这里(因为我仍然从中获得很小的版税)。因此,除了发布文章之外,我不会发布指向我在英国SQLBits上发表的有关优化器如何在较高水平下工作的演讲的链接,因此您可以根据需要更详细地了解搜索的不同主要阶段了解这一点。这是视频链接:https : //sqlbits.com/Sessions/Event6/inside_the_sql_server_query_optimizer

  • 我相信“1”也会经历同样的扩展。我基于这里的性能测试 /sf/ask/111820971/#6140367 还可以看到使用“1”失败的查询答案中的示例当列级权限发挥作用时意外 (2认同)

Nak*_*ary 17

COUNT(*)并且COUNT(1)在结果和性能的情况一样.


Ric*_*ard 12

我希望优化者能够确保在奇怪的边缘情况之外没有真正的区别.

与任何事情一样,唯一真实的方法是衡量您的具体案例.

那就是说,我一直都在使用COUNT(*).


Tho*_*ner 10

随着这个问题一再出现,这里还有一个答案.我希望在这里为初学者添加一些想知道"最佳实践"的东西.

SELECT COUNT(*) FROM something 计算记录是一项简单的任务.

SELECT COUNT(1) FROM something 检索每个记录1,并计算非空的1,这实际上是计数记录,只是更复杂.

话虽如此:好的dbms注意到第二个语句将导致与第一个语句相同的计数并相应地重新解释它,以免做不必要的工作.因此,通常两个语句都会产生相同的执行计划并花费相同的时间.

但是从可读性的角度来看,您应该使用第一个语句.您想要计算记录,因此计算记录而不是表达式.仅当您想要计算某些事物的非空出现时才使用COUNT(表达式).


RBT*_*RBT 8

我在8 GB RAM hyper-v盒子上对SQL Server 2012进行了快速测试.您可以自己查看结果.在运行这些测试时,我没有运行除SQL Server Management Studio之外的任何其他窗口应用程序.

我的表架构:

CREATE TABLE [dbo].[employee](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_employee] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
Run Code Online (Sandbox Code Playgroud)

Employee表中记录总数:178090131(约1.78亿行)

第一个查询:

Set Statistics Time On
Go    
Select Count(*) From Employee
Go    
Set Statistics Time Off
Go
Run Code Online (Sandbox Code Playgroud)

第一次查询的结果:

 SQL Server parse and compile time: 
 CPU time = 0 ms, elapsed time = 35 ms.

 (1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 10766 ms,  elapsed time = 70265 ms.
 SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
Run Code Online (Sandbox Code Playgroud)

第二个查询:

    Set Statistics Time On
    Go    
    Select Count(1) From Employee
    Go    
    Set Statistics Time Off
    Go
Run Code Online (Sandbox Code Playgroud)

第二次查询的结果:

 SQL Server parse and compile time: 
   CPU time = 14 ms, elapsed time = 14 ms.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 11031 ms,  elapsed time = 70182 ms.
 SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
Run Code Online (Sandbox Code Playgroud)

您可以注意到存在83(= 70265 - 70182)毫秒的差异,这可以很容易地归因于运行查询时的确切系统条件.我也进行了一次运行,所以如果我进行多次运行并进行一些平均,这种差异将变得更加准确.如果对于如此庞大的数据集,差异将小于100毫秒,那么我们可以很容易地得出结论,这两个查询没有SQL Server引擎所展示的任何性能差异.

注意:两次运行中RAM的使用率接近100%.在开始两次运行之前,我重新启动了SQL Server服务.


小智 7

SET STATISTICS TIME ON

select count(1) from MyTable (nolock) -- table containing 1 million records. 
Run Code Online (Sandbox Code Playgroud)

SQL Server执行时间:
CPU时间= 31毫秒,已用时间= 36毫秒.

select count(*) from MyTable (nolock) -- table containing 1 million records. 
Run Code Online (Sandbox Code Playgroud)

SQL Server执行时间:
CPU时间= 46 ms,已用时间= 37 ms.

我已经运行了数百次,每次都清除缓存.随着服务器负载的变化,结果会不时变化,但几乎总是count(*)有更高的CPU时间.

  • 我无法重现这一点.`count(*)`和`count(1)`在我的SQL 2008实例中,即使在计算具有450万行的表时,也会在几毫秒内返回结果. (14认同)
  • 有时,在某些系统中,首先运行的语句总是运行得更快...您是否随机化了它们运行的​​顺序? (2认同)

Dhe*_*rik 6

有一篇文章表明COUNT(1)on Oracle只是 的别名COUNT(*),并提供了相关证明。

\n

我将引用一些部分:

\n
\n

数据库软件中有一部分叫做\xe2\x80\x9c的\nOptimizer\xe2\x80\x9d,官方文档中定义为\n\xe2\x80\x9c内置的数据库软件,决定了最执行 SQL 语句\xe2\x80\x9c 的有效方法。

\n

优化器的组件之一称为 \xe2\x80\x9c 转换器\xe2\x80\x9d,\n其作用是确定将\n原始 SQL 语句重写为语义上等效的 SQL 语句是否有利\n这可能是更高效。

\n

您想了解当您使用 COUNT(1) 编写\n查询时优化器会执行什么操作吗?

\n
\n

对于具有特权的用户ALTER SESSION,您可以放置​​一个tracefile_identifier,启用优化器跟踪并运行COUNT(1)选择,例如:SELECT /* test-1 */ COUNT(1) FROM employees;

\n

之后,您需要本地化跟踪文件,可以用什么来完成SELECT VALUE FROM V$DIAG_INFO WHERE NAME = \'Diag Trace\';. 稍后在该文件中,您会发现:

\n
SELECT COUNT(*) \xe2\x80\x9cCOUNT(1)\xe2\x80\x9d FROM \xe2\x80\x9cCOURSE\xe2\x80\x9d.\xe2\x80\x9dEMPLOYEES\xe2\x80\x9d \xe2\x80\x9cEMPLOYEES\xe2\x80\x9d\n
Run Code Online (Sandbox Code Playgroud)\n

正如你所看到的,它只是一个别名COUNT(*)

\n

另一个重要的评论:二十年前COUNT(*)确实更快,在 Oracle 7.3 之前,Oracle 的

\n
\n

自 7.3 起,Count(1) 已被重写为 count(*),因为 Oracle 喜欢\n自动调整神话语句。在早期的 Oracle7 中,在 DETERMINISTIC 和 NON-DETERMINISTIC 存在之前,oracle 必须将每一行作为函数求值 (1)。

\n

所以二十年前,count(*) 更快

\n
\n

对于其他数据库如Sql Server,应该单独研究。

\n

我知道这个问题是针对 SQL Server 的,但是关于同一主题的其他问题(不提及特定数据库)已关闭并标记为与此答案重复。

\n