计数(*)与计数(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 something
logging是一件容易的事情。
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