是的,我知道这个问题类似于这个线程:COUNT(*) vs. COUNT(1) vs. COUNT(pk):哪个更好?,但这有点不同。
我的学长说count(PrimaryKey)
,假设PrimaryKey
不可能NULL
,从那里得到结果比做一个正常的要快count(*)
。这是真的?
如果这是真的,那么是否适用于所有 RDBMS?如果可能,请参考(半)官方文档。
是的,我知道这个问题类似于这个线程:COUNT(*) vs. COUNT(1) vs. COUNT(pk):哪个更好?,但这有点不同。
我的学长说count(PrimaryKey)
,假设PrimaryKey
不可能NULL
,从那里得到结果比做一个正常的要快count(*)
。这是真的?
如果这是真的,那么是否适用于所有 RDBMS?如果可能,请参考(半)官方文档。
不,这似乎是一个持续存在的误解,基于语法之间的混淆
SELECT * FROM ...
和
SELECT COUNT(*) FROM ...
在第一种情况下,*
引用所有列,返回这些肯定比返回单个列需要更多的资源。在第二种情况下,COUNT(*)
它只是“计算所有行数”的简写。错误的信念是,它COUNT(*)
以某种方式指示数据库引擎检查所有行中的所有列,而COUNT(<pk_field>)
只需要查看一列。
这里还有许多其他关于 SO 的评论引用了 SQL-92 标准,该标准明确指出COUNT(*)
应该只引用表的基数,因此,至少在理论上,数据库引擎应该能够识别和优化它。
据我所知,在这两种情况下,大多数数据库引擎(Postgres、Oracle、MySQL InnoDB)只会执行索引扫描来计算行数。如果您指定 PK,则将使用该索引;如果您只使用COUNT(*)
,则查询计划器将选择一个跨越整个表的索引*,但性能应该相同。
我能找到的唯一例外是带有 MyISAM 表的 MySQL——这些表缓存了行数,所以COUNT(*)
速度非常快。但是,查询计划器也将COUNT(<field>)
, where <field>
is any non-null column 识别为对完整表大小的请求,并在这种情况下也使用缓存。(来源)同样,性能没有差异。
*理论上,如果你没有这样的索引,那么COUNT(*)
会很慢,但在那种情况下,COUNT(<pk>)
根据定义是不可能的
没关系有几个原因。首先,两种符号——COUNT(1)
和COUNT(*)
——都是错误的语法。考虑关于SUM
聚合的相同问题。哦,SUM(*)
没有任何意义;为什么?因为,求和是赋值的迭代执行
for( int columnValue : columnList )
currentSum = currentSum + columnValue;
而对于COUNT
聚合它看起来像这样
for( Tuple t : tupleList )
currentSum = currentSum + 1;
因此,COUNT
聚合根本不应该有任何参数!
然后,有各种各样的句法怪癖,比如count distinct。这仅仅证明了 SQL 设计者的无能,他们试图将两个连续的操作(选择不同的元组,然后聚合)压缩到一个操作中。
无关紧要的第二个原因是,在实践中您会遇到无数性能不佳的查询,而COUNT(1)
vsCOUNT(*)
从来都不是瓶颈。