【问题标题】:is there any performance improvement on doing count(PK) against count(*) [duplicate]对计数(*)进行计数(PK)是否有任何性能改进[重复]
【发布时间】:2012-09-06 16:31:54
【问题描述】:

是的,我知道这个问题与此线程相似:COUNT(*) vs. COUNT(1) vs. COUNT(pk): which is better?,但这有点不同。

我的前辈说从count(PrimaryKey) 得到结果,假设PrimaryKey 不能是NULL,在某种程度上比做一个普通的count(*) 更快。这是真的吗?

如果这是真的,那么对于所有 RDBMS 来说都是真的吗?可以的话请参考(半)官方文档。

【问题讨论】:

  • @Ian:你真的读过我关于它可能相似的第一个声明吗?
  • 我做了,然后在某处忘记了它——抱歉,我会通过一些研究来弥补你的损失:)

标签: count relational-database


【解决方案1】:

没有。这似乎是一个持续存在的误解,基于语法之间的混淆

SELECT * FROM ...

SELECT COUNT(*) FROM ...

在第一种情况下,* 引用所有列,返回这些肯定比返回单个列需要更多资源。在第二种情况下,COUNT(*) 只是“计算所有行数”的简写。错误的信念是COUNT(*) 以某种方式指示数据库引擎检查所有行中的所有列,而COUNT(<pk_field>) 只需要查看一列。

SO 上还有许多其他 cmets 引用 SQL-92 标准,该标准明确指出 COUNT(*) 应该只引用表的基数,因此,至少在理论上,数据库引擎应该能够识别并优化它。

据我所知,在这两种情况下,大多数数据库引擎(PostgresOracleMySQL InnoDB)只会执行索引扫描来计算行数。如果您指定 PK,则将使用该索引;如果你只使用COUNT(*),那么查询规划器会选择一个跨越整个表的索引*,但性能应该是相同的。

我能找到的唯一例外是 MySQL 和 MyISAM 表——这些表缓存行数,所以COUNT(*) 非常快。但是,查询计划器也将COUNT(<field>)(其中<field> 是任何非空列)识别为对完整表大小的请求,并且在这种情况下也使用缓存。 (source) 同样,性能没有差异。

* 理论上,如果你没有这样的索引,那么COUNT(*) 会很慢,但在这种情况下,COUNT(<pk>) 就不可能了

【讨论】:

    【解决方案2】:

    这并不重要,有几个原因。首先,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)COUNT(*) 从来都不是瓶颈。

    【讨论】:

    • COUNT 需要一个可选参数 -- 如果给定,它将不计算表达式计算结果为 NULL 的行 -- 参见 postgresql.org/docs/9.2/static/functions-aggregate.html
    • 那么,你不能先过滤掉空值,然后再计数吗?换句话说,您只需一次解释两个操作的组成,而不是为每个使用场景引入笨拙的语法。
    • 所有 SQL 聚合函数都会跳过空值:SUMCOUNTMINMAXAVERAGE 等。COUNT(*) 是奇数。如果您必须先过滤,您将无法执行 SELECT COUNT(column_a), COUNT(column_b) FROM table 之类的操作来计算两个不同列中的非空值
    • 当然可以:select sum(case when mgr is null then 0 else 1 end) cmgr, sum(case when comm is null then 0 else 1 end) csal from emp
    • 其实我问的是count(PK),而不是count(1)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 2019-07-17
    • 2021-03-17
    相关资源
    最近更新 更多