count(1) 比 count(*) 效率高么

1)有 Where 条件的 count,会根据结果count 一下所有的行数,其性能更依赖于你的 Where 条件,所以文章我们仅针对没有 Where 的情况进行说明。

MyISAM 引擎会把一个表的总行数记录了下来,所以在执行 count(*) 的时候会直接返回数量,执行效率很高。在 MySQL 5.5 以后默认引擎切换为 InnoDB,InnoDB 因为增加了版本控制(MVCC)的原因,同时有多个事务访问数据并且有更新操作的时候,每个事务需要维护自己的可见性,那么每个事务查询到的行数也是不同的,所以不能缓存具体的行数,他每次都需要 count 一下所有的行数。那么 count(1) 和 count(*)有区别么?
InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference. 这是官网的解释,所以两种实现其实一样,那么具体为什么一样呢?
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_count

探究这个问题首先我们需要理解 count 的含义,如下是官网给出的定义
Returns a count of the number of non-NULL values of expr in the rows retrieved by a SELECT statement. 
The result is a BIGINT value.
大致的解释是返回 SELECT 语句检索的行中 expr 的非 NULL 值的计数,到这里我们就明白了,首先它是一个聚合函数,然后对 SELECT 的结果集进行计数,但是需要参数不为 NULL。那么我们继续阅读官网的内容:
COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values.
大致的内容是说,count(*) 不同,他不关心这个返回值是否为空都会计算他的count,因为 count(1) 中的 1 是恒真表达式,那么 count(*) 还是 count(1) 都是对所有的结果集进行 count,所以他们本质上没有什么区别。

当然这个地方 InnoDB 本身也做了一些优化,它会使用最小的二级索引来进行 count 的查询优化。如果没有二级索引才会选择聚簇索引,这样的设计单从 IO 的角度就节省了很多开销。

到这里我们明白了 count(*) 和 count(1) 本质上面其实是一样的,那么 count(column) 又是怎么回事呢?
count(column) 也是会遍历整张表,但是不同的是它会拿到 column 的值以后判断是否为空,然后再进行累加,那么如果针对主键需要解析内容,如果是二级所以需要再次根据主键获取内容,又是一次 IO 操作,所以 count(column) 的性能肯定不如前两者喽,如果按照效率比较的话:count(*)=count(1)>count(primary key)>count(column)

既然 count(*) 在查询上依赖于所有的数据集,是不是我们在设计上也需要尽量的规避全量 count 呢?通常情况我们针对可预见的 count 查询会做适当的缓存,可以是 Redis,也可以是独立的 MySQL count 表,当然无论是哪种方式我们都需要考虑一致性的问题。
 

2)sql调优,主要是考虑降低:consistent gets和physical reads的数量。

count(1)与count(*)比较:

如果你的数据表没有主键,那么count(1)比count(*)快
如果有主键的话,那主键(联合主键)作为count的条件也比count(*)要快
如果你的表只有一个字段的话那count(*)就是最快的啦
count(*) count(1) 两者比较。主要还是要count(1)所相对应的数据字段。
如果count(1)是聚索引,id,那肯定是count(1)快。但是差的很小的。
因为count(*),自动会优化指定到那一个字段。所以没必要去count(?),用count(*),sql会帮你完成优化的

count详解:

count(1)count(主键)一样,只扫描主键。

count(*)count(非主键)

  count(*)将返回表格中所有存在的行的总数包括值为null的行,然而count(列名)将返回表格中除去null以外的所有行的总数(有默认值的列也会被计入).
  distinct 列名,得到的结果将是除去值为null和重复数据后的结果

count(主键) 不一定比count(其余索引) 快: 

索引是一种B+树的结构,以块为单位进行存储。假设块大小是1K,主键索引大小为4B,有一个字段A的索引大小为2B。 
同样一个块,能存放256个主键索引,但是能存放512个字段A的索引。 
假设总数据是2K条,意味着主键索引占用了8个块,而A字段索引占用了4个块,统计时用主键索引需要经历的块多,IO次数多。效率也比A字段索引慢。

总结

1.如果在开发中确实需要用到count()聚合,那么优先考虑count(*),因为mysql数据库本身对于count(*)做了特别的优化处理。
有主键或联合主键的情况下,count(*)略比count(1)快一些。 
   没有主键的情况下count(1)比count(*)快一些。 
   如果表只有一个字段,则count(*)是最快的。
2. 使用count()聚合函数后,最好不要跟where age = 1;这样的条件,会导致不走索引,降低查询效率。除非该字段已经建立了索引。使用count()聚合函数后,若有where条件,且where条件的字段未建立索引,则查询不会走索引,直接扫描了全表。 
3. count(字段),非主键字段,这样的使用方式最好不要出现。因为它不会走索引

 

3)count(*) 和 count(1)和count(列名)区别 

执行效果上: 
1.count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL  
2.count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL  
3.count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计 

执行效率上:  
1.列名为主键,count(列名)会比count(1)快  
2.列名不为主键,count(1)会比count(列名)快  
如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*)  
3.如果有主键,则 select count(主键)的执行效率是最优的  
如果表只有一个字段,则 select count(*)最优  


原文链接:
https://mp.weixin.qq.com/s/Rwpke4BHu7Fz7KOpE2d3Lw
https://www.cnblogs.com/jixp/articles/6690445.html
https://eeeewwwqq.iteye.com/blog/1972576

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: count(1)和count(*)都是用来统计行数的函数,但是它们的区别在于: 1. count(1)是指统计所有行中第一个非空字段的值的数量,因为1是一个常量,所以它不会对查询产生影响,所以count(1)的效率比count(*)高。 2. count(*)是指统计所有行的数量,包括空行,所以它的效率比count(1)低,但是它可以统计所有行的数量,包括空行,所以在某些情况下,count(*)更加实用。 总的来说,如果只是统计行数,建议使用count(1),因为它的效率更高。如果需要统计所有行的数量,包括空行,那么就使用count(*)。 ### 回答2: MySQL中的count()函数用于返回指定列中的行数。在具体使用时,可以将一个或多个列作为参数,以确定要统计行数的数据集。 在MySQL中,当我们使用count(1)和count(*)统计数据集的行数时,它们的作用是相同的,因为两者都返回所选列中非null值的计数。只不过内部处理方式略有不同。 count(*)操作会扫描整张表,Mysql会遍历整张表,但这个操作会忽略所有的列值。而count(1)操作不会忽略索引,它会遍历索引树。 所以在查询1个表的数据总行数的时候,无论是count(*)还是count(1),他们的结果是相同的,不过在涉及到查询其他的操作时,建议优先使用count(1),避免浪费查询时间。 总之,在实际使用中,count(*)和count(1)的区别并不明显,它们都是用来统计数据行数的常见SQL操作。但如果你需要在查询语句中指定特定列,则建议使用count(1),因为这样会更快一些。如果你需要在同一查询语句中多次使用count函数,则建议统一使用count(*),以保证查询效率,在处理多表关联查询时,尽量避免使用count(*)来统计行数,避免查询效率低下的情况的发生。 ### 回答3: 在MySQL中,count(1)和count(*)都是用于计算数据表中的行数的函数。它们看起来相似,但实际上在某些情况下有一些区别。 count(1)是将每一行都用值1代替,一旦遇到非空值,则计数加1。这实际上是对空间的浪费,因为在计算每行的值时,实际上是没有用到这个1值的。因此,使用count(1)会占用更多的空间,从而降低查询性能。 相反,count(*)是计算表中所有行数的函数,它不会像count(1)一样替换每行的值。因此,它不会浪费空间,效率更高。 但是,这两种函数的在执行SQL查询时会根据MySQL的优化器来进行优化,因此在某些情况下两者之间的性能差异可能会很小。 总的来说,对于计算数据表中行数的操作,建议使用count(*),这将是更高效和更准确的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值