计数(*)与计数(1)

只是想知道你们中的任何一个人是否使用Count(1)不是Count(*)并且如果在性能上有明显的差别,或者这只是从过去的日子中提出的遗留习惯?

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

没有区别。

原因:

在线书籍显示 “ COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )

“1”是一个非空的expression式,所以它和COUNT(*) 。 优化器认识到它是什么:微不足道。

EXISTS (SELECT * ...相同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 

同样的IO,相同的计划,作品

编辑,2011年8月

关于DBA.SE的类似问题 。

编辑,2011年12月

在ANSI-92中特别提到COUNT(*) (查找“ Scalar expressions 125 ”)

案件:

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

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

b)否则,令TX为单列表格,这是将<值expression式>应用于T的每一行并消除空值的结果。 如果一个或多个空值被消除,则提出完成条件:警告 –

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

与stream行的观点相反,在甲骨文他们也是如此。

Oracle中的SYS_GUID()是相当计算量的函数。

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

这个查询:

 SELECT COUNT(SYS_GUID()) FROM t_even 

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

但是,这个查询:

 SELECT COUNT(*) FROM ( SELECT SYS_GUID() FROM t_even ) 

运行了2秒钟,因为它甚至不试图评估SYS_GUID() (尽pipe*是作为COUNT(*)参数)

显然,COUNT(*)和COUNT(1)将始终返回相同的结果。 因此,如果一个人比另一个人慢,这实际上是由于一个优化器错误。 由于这两种forms在查询中使用非常频繁,因此DBMS允许这样的错误不能保持不变。 因此,您会发现两种表单的性能在所有主要SQL DBMS中可能都是相同的。

在SQL-92标准中, COUNT(*)具体表示“expression式的基数”(可以是基表,VIEW,派生表,CTE等)。

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

同样,熟悉SQL标准的人类编码人员可以很容易地selectCOUNT(*) ,在处理多个供应商的SQL产品时这是一项有用的技能。

另外,在特殊情况下SELECT COUNT(*) FROM MyPersistedTable; ,这个想法是DBMS很可能会统计表的基数。

因此,由于COUNT(1)COUNT(*)在语义上是等价的,我使用COUNT(*)

COUNT(*)COUNT(1)在结果和性能方面相同。

我希望优化器可以确保在奇怪边缘情况下没有真正的区别。

与其他任何事情一样,唯一真正的方法就是衡量你的具体情况。

这就是说,我一直使用COUNT(*)

 SET STATISTICS TIME ON select count(1) from MyTable (nolock) -- table containing 1 million records. 

SQL Server执行时间:
CPU时间= 31 ms,经过时间= 36 ms。

 select count(*) from MyTable (nolock) -- table containing 1 million records. 

SQL Server执行时间:
CPU时间= 46毫秒,经过时间= 37毫秒。

我已经跑了这个数百次了,每次都要清除caching。由于服务器负载的变化,结果会不时变化,但是几乎总是计数(*)的CPU时间更长。

我在8 GB RAM hyper-v盒子上运行SQL Server 2012的快速testing。 你可以看到自己的结果。 在运行这些testing时,除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 

Employee表中的logging总数:178090131(约1.78亿行)

第一个查询:

 Set Statistics Time On Go Select Count(*) From Employee Go Set Statistics Time Off Go 

第一个查询的结果:

  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. 

第二个查询:

  Set Statistics Time On Go Select Count(1) From Employee Go Set Statistics Time Off Go 

第二个查询的结果:

  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. 

您可以注意到有83(= 70265 – 70182)毫秒的差异可以很容易地归因于查询运行时的确切的系统条件。 我也做了一个单一的运行,所以如果我做几次运行并做一些平均的话,这个差别就会变得更加准确。 如果对于这样一个巨大的数据集来说,差异小于100毫秒,那么我们可以很容易地得出这两个查询没有任何性能差异的SQL Server引擎。

注意 :在两次运行中,RAM的命中率接近100%。 在启动这两个运行之前,我重新启动了SQL Server服务。

由于这个问题一再出现,这里还有一个答案。 我希望在这里为初学者增添一些想知道“最佳实践”的东西。

SELECT COUNT(*) FROM somethinglogging是一件容易的事情。

SELECT COUNT(1) FROM something检索每个logging1,然后计数不为null的1,这实际上是计数logging,只是更复杂。

说了这样的话:好的dbms注意到第二个陈述会导致与第一个陈述相同的计数,并相应地重新解释,因为不做不必要的工作。 所以通常这两个语句会导致相同的执行计划并花费相同的时间。

但是从可读性的angular度来看,您应该使用第一条语句。 你想计数logging,所以计数logging,而不是expression式。 只有当你想计算非null事件的发生时,才使用COUNT(expression式)。

轻松演示COUNT(*)与COUNT(<some col>) –

 USE tempdb; GO IF OBJECT_ID( N'dbo.Blitzen', N'U') IS NOT NULL DROP TABLE dbo.Blitzen; GO CREATE TABLE dbo.Blitzen (ID INT NULL, Somelala CHAR(1) NULL); INSERT dbo.Blitzen SELECT 1, 'A'; INSERT dbo.Blitzen SELECT NULL, NULL; INSERT dbo.Blitzen SELECT NULL, 'A'; INSERT dbo.Blitzen SELECT 1, NULL; SELECT COUNT(*), COUNT(1), COUNT(ID), COUNT(Somelala) FROM dbo.Blitzen; GO DROP TABLE dbo.Blitzen; GO