只是想知道您是否有人用光Count(1)
了Count(*)
,性能是否存在明显差异,或者这仅仅是过去的日子所养成的传统习惯?
具体的数据库是SQL Server 2005
。
只是想知道您是否有人用光Count(1)
了Count(*)
,性能是否存在明显差异,或者这仅仅是过去的日子所养成的传统习惯?
具体的数据库是SQL Server 2005
。
Answers:
没有区别。
原因:
在线书籍上说“
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
相同的IO,相同的计划,作品
编辑,2011年8月
编辑,2011年12月
COUNT(*)
在ANSI-92中专门提到(请查找“ Scalar expressions 125
”)
案件:
a)如果指定了COUNT(*),则结果为T的基数。
就是说,ANSI标准将其识别为明显的含义。由于这种迷信COUNT(1)
,RDBMS供应商对其进行了优化。否则将按照ANSI进行评估
b)否则,将TX设为单列表,该表是将<value expression>应用于T的每一行并消除空值的结果。如果消除了一个或多个空值,则会引发完成条件:warning-
在SQL Server中,这些语句产生相同的计划。
与流行观点相反,在Oracle中,它们也这样做。
SYS_GUID()
Oracle中的计算功能相当密集。
在我的测试数据库中,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()
(尽管*
是的参数COUNT(*)
)
SYS_GUID()
至少(一次)准确地评估一次子查询以返回结果,对吗?
COUNT(*)
取决于的值SYS_GUID
?
COUNT(*)
要运行,它需要一个表,因此子查询应该像一个查询。否则,我看不到COUNT(*)
返回有意义的值的方法
map
方法的作用,那么您是否看到这两个表达式:t_even.map(() => sys_guid()).length
并且t_even.length
总是返回相同的值?Oracle的优化器足够聪明,可以看到它并优化map
零件。
length
不太依赖什么样的收集包括,只是它的元素的数量。如果此数字存储在集合的元数据中(Oracle或大多数其他现代RDBMS并非如此,而旧MySQL的存储引擎MyISAM就是这种情况),则COUNT(*)
只需从元数据中获取值即可。
显然,COUNT(*)
并且COUNT(1)
将始终返回相同的结果。因此,如果一个慢于另一个,那实际上是由于优化程序错误所致。由于两种形式的查询都非常频繁地使用,因此DBMS不允许此类错误保持未解决状态是没有意义的。因此,您会发现两种形式的性能在所有主要的SQL DBMS中都是(可能)相同的。
我在SQL Server团队中工作,我希望可以澄清该线程中的几点(我以前没有看到过,所以对不起工程团队以前没有这样做)。
首先,select count(1) from table
vs与之间没有语义差异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
在SQL-92标准中, COUNT(*)
专门表示“表表达式的基数”(可以是基表,VIEW,派生表,CTE等)。
我想这个想法很COUNT(*)
容易解析。使用任何其他表达式都需要解析器确保其不引用任何列(COUNT('a')
在哪里a
是文字,COUNT(a)
在哪里a
可以产生不同的结果)。
同样,COUNT(*)
熟悉SQL标准的人类程序员也可以轻松地挑选出来,这是与多个供应商提供的SQL产品一起使用时的一项有用技能。
同样,在特殊情况下SELECT COUNT(*) FROM MyPersistedTable;
,思想是DBMS可能会保存表基数的统计信息。
因此,由于COUNT(1)
和COUNT(*)
在语义上是等效的,因此我使用COUNT(*)
。
我希望优化器确保在奇怪的边缘情况下没有真正的区别。
像其他任何事情一样,唯一真实的说法就是衡量您的具体案例。
就是说,我一直都习惯COUNT(*)
。
随着这个问题一遍又一遍地出现,这里是另一个答案。我希望为初学者增加一些关于“最佳实践”的信息。
SELECT COUNT(*) FROM something
计算记录很容易。
SELECT COUNT(1) FROM something
每条记录检索1,然后计算不为null的1(实际上是对记录进行计数),只是更为复杂。
话虽如此:好的dbms注意,第二条语句将产生与第一条语句相同的计数,并相应地重新解释它,以免进行不必要的工作。因此,通常这两个语句将导致相同的执行计划并花费相同的时间。
但是,从可读性的角度来看,您应该使用第一条语句。您要对记录进行计数,因此要对记录而不是表达式进行计数。仅当您要计算某事的非空出现次数时,才使用COUNT(表达式)。
我在SQL Server 2012的8 GB RAM hyper-v盒上进行了快速测试。您可以自己查看结果。在运行这些测试时,除了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
表中的记录总数: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 Engine表现出的任何性能差异。
注意:两次运行中,RAM命中率接近100%。在开始两个运行之前,我重新启动了SQL Server服务。
SET STATISTICS TIME ON
select count(1) from MyTable (nolock) -- table containing 1 million records.
SQL Server执行时间:
CPU时间= 31毫秒,经过的时间= 36毫秒。
select count(*) from MyTable (nolock) -- table containing 1 million records.
SQL Server执行时间:
CPU时间= 46毫秒,经过的时间= 37毫秒。
我已经运行了数百次,每次都清除高速缓存。随着服务器负载的变化,结果有时会不尽相同,但几乎总是count(*)
会有更高的cpu时间。
count(*)
并且count(1)
在我的SQL 2008实例中,即使在计数包含450万行的表时,也可以在几毫秒内返回结果。
有一篇文章表明COUNT(1)
on Oracle只是的别名COUNT(*)
,并对此进行了证明。
我会引用一些部分:
数据库软件的一部分称为“优化程序”,在官方文档中定义为“确定执行SQL语句最有效方式的内置数据库软件”。
优化程序的组件之一称为“转换器”,其作用是确定将原始SQL语句重写为语义上等效的SQL语句(可能更有效)是否有利。
您想查看使用COUNT(1)编写查询时优化器的作用吗?
对于具有ALTER SESSION
特权的用户,您可以放置tracefile_identifier
,启用优化程序跟踪并运行COUNT(1)
select,例如:SELECT /* test-1 */ COUNT(1) FROM employees;
。
之后,您需要本地化跟踪文件,可以使用做什么SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';
。在文件的后面,您将找到:
SELECT COUNT(*) “COUNT(1)” FROM “COURSE”.”EMPLOYEES” “EMPLOYEES”
如您所见,它只是的别名COUNT(*)
。
另一个重要的评论:在Oracle 7.3之前的20年前,在Oracle上的COUNT(*)
速度确实更快:
自7.3起,Count(1)已被重写为count(*),因为Oracle喜欢自动调整神话语句。在较早的Oracle7中,oracle必须在存在DETERMINISTIC和NON-DETERMINISTIC之前,对每行的函数求值(1)。
所以二十年前,count(*)更快
对于另一个数据库(如Sql Server),应针对每个数据库分别进行研究。
我知道这个问题是特定于Sql Server的,但是关于同一主题的其他问题(不提及数据库)已被关闭,并标记为该答案的重复项。
在所有RDBMS中,两种计数方式在产生的结果方面都是等效的。关于性能,我没有观察到SQL Server的任何性能差异,但是可能值得指出的是,某些RDBMS(例如PostgreSQL 11)在COUNT(1)
检查参数表达式的可为空性时,对它们的最佳实现不太理想,如本文所见。
我发现运行时1M行的性能差异为10%:
-- Faster
SELECT COUNT(*) FROM t;
-- 10% slower
SELECT COUNT(1) FROM t;
如果有的话,COUNT(1)与COUNT(*)并没有太大的不同。关于计数可为空的列的问题,这可以很容易地演示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