MySQL:SELECT COUNT 小结

本文介绍了MySQL中COUNT(字段)、COUNT(1)和COUNT(*)的区别及性能,重点讨论了MyISAM和InnoDB引擎在处理COUNT时的差异。COUNT(*)是SQL92标准,通常具有最优效率。在判断数据是否存在时,推荐使用LIMIT 1代替COUNT以避免全表扫描。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看看COUNT(*),MyISAM 引擎会把一个表的总行数记录了下来,所以在执行 COUNT(*)的时候会直接返回数量,执行效率很高。对于InnoDB这样的事务性存储引擎, 因为增加了版本控制(MVCC)的原因,同时有多个事务访问数据并且有更新操作的时候,每个事务需要维护自己的可见性,那么每个事务查询到的行数也是不同的,所以不能缓存具体的行数,他每次都需要count计算一下所有的行数。

如果您正在学习Spring Boot,推荐一个连载多年还在继续更新的免费教程:http://blog.didispace.com/spring-boot-learning-2x/

至于 COUNT(1) 和 COUNT(*)有什么区别呢,根据官网的内容(即上述截图倒数第二段),两种实现上其实一样:

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

因为COUNT(*) 不care返回值是否为空都会将改行纳入计算,所以他count了所有行数,而 COUNT(1) 中的 1 ,则是遇到了行的时候为恒真表达式,所以 COUNT(*) 还是 COUNT(1) 都是对所有的结果集进行 count,他们本质上没有什么区别。姑且认为 COUNT(*)≈ COUNT(1)。

关于COUNT(字段)

我们再来看看的C 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 OUNT(字段),他的查询就简单粗暴了,就是进行全表扫描,然后判断拿到的字段的值是不是为NULL,不为NULL则累加。

相比COUNT(*),COUNT(字段)多了一个步骤就是判断所查询的字段是否为NULL,所以他的性能要比COUNT(*)COUNT(1)慢。

总结

综上,COUNT(1)和 COUNT(*)表示的是直接查询符合条件的数据库表的行数。而COUNT(字段)表示的是查询符合条件的列的值,并判断不为NULL的行数的累计,效率自然会低一点,

除了查询得到结果集有区别之外,相比COUNT(1) 和 COUNT(字段)来讲,COUNT(*)是SQL92定义的标准统计数的语法,是官方提供的标准方案,基于此,MySQL数据库对他进行过很多优化。

注:SQL92,是数据库的一个ANSI/ISO标准。它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)。

下面是对一张具有3400W数据的表的统计过程,comid是整型,可以对比下执行效率差异:

使用建议

根据总结的内容,从效率层面说,COUNT(*)≈ COUNT(1) > COUNT(字段),又因为 COUNT(*)是SQL92定义的标准统计数的语法,我们建议使用 COUNT(*)。

我们再来看看MySQL数据库做了哪些优化:以MySQL中比较常用的执行引擎InnoDB和MyISAM为例子。

1、MyISAM不支持事务,MyISAM中的锁是表级锁;

因为MyISAM的锁是表级锁,所以同一张表上面的操作是串行执行的,MyISAM把表的总行数单独记录下来,如果只是使用COUNT(*)对表进行查询的时候,可以直接返回这个记录的数值就可以了。

这样表中总行数记录即可提供给COUNT(*)查询使用,又因MyISAM数据库是表级锁,数据库行数不会被并行修改,所以行数是准确无误的。

如果您正在学习Spring Boot,推荐一个连载多年还在继续更新的免费教程:http://blog.didispace.com/spring-boot-learning-2x/

2、InnoDB支持事务,其中大部分操作都是行级锁。

这样就不能愉快的做这种缓存操作了,因为表的行数可能会被并发修改,缓存记录下来的总行数就不准确了。

在InnoDB中,使用COUNT(*)查询行数的时候,不需要进行扫表,只要获取记录行数而已。所以官方在针对InnoDB的 SELECT COUNT(*) FROM语句执行过程,会自动选择一个成本较低的索引进行的话,这样就可以大大节省时间。

InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值,非聚簇索引要比聚簇索引小很多,MySQL会优先选择最小的非聚簇索引来扫表,这样可以保证COUNT(*)的最优效率。

当查询语句中包含WHERE以及GROUP BY条件,会有一些其他的因素影响,所以要综合考虑。

判断数据在否,COUNT怎么用?

上面那种很获取COUNT数的场景多用于数据分页,数据统计的场景,有很多的情况则是直接判断数据是否存在,这种情况下,其实是不关心有多少数据。但是我们CoreReview的时候还是会很经常看到这种做法:

select COUNT(*) from test_ucsyncdetail where comid > 520;

int count = testDao.CountByComId(comId);

if(count>0){

//存在,则执行存在分支的代码

}else{

//不存在,则执行存在分支的代码

}

更好的写法应该是这样:

select 1 from test_ucsyncdetail where comid > 520 limit1;

Object tda = testDao.checkExit(comId);

if(tda !=null){

//存在,则执行存在分支的代码

}else{

//不存在,则执行存在分支的代码

}

规避了SQL使用COUNT表达式扫表的操作,而是改用SELECT 1 ... LIMIT 1,数据库查询时遇到一条就返回,不会再继续查找和执行,如果存在传输回一条结果为1的数据 ,否则为null,业务代码中直接判断是否非空即可

往期推荐

### MySQLCOUNT 函数的使用方法 #### 一、基本概念 COUNT 是一种聚合函数,在 MySQL 数据库查询中用来统计指定列不为空的记录总数。此功能不仅限于简单计数,还可以配合其他子句实现复杂的数据筛选与汇总操作[^1]。 #### 二、不同形式及其特点 - **`COUNT(*)`**: 统计表内所有行的数量,无论任何字段是否有NULL值都会被计入。 - **`COUNT(column)` 或 `COUNT(1)`**: 只有当给定的 column 不为 NULL 时才会被计算进去;而 `COUNT(1)` 则表示每遇到一条有效记录就加一次计数。值得注意的是,尽管存在细微差别,但在实际应用中两者的效率几乎相等,并且会被 MySQL 的优化机制视为同义表达方式[^3]。 ```sql -- 计算员工数量(即使某些职位可能未填写) SELECT COUNT(position) AS position_count FROM employees; -- 对比之下,下面这条语句会给出整个表格的确切行数 SELECT COUNT(*) AS total_rows FROM employees; ``` #### 三、结合条件过滤 为了获取更加精确的结果集大小,可以利用 WHERE 来限定范围内的条目数目: ```sql -- 查询工资超过8000美元的人数 SELECT COUNT(*) as high_salary_employees FROM staff WHERE salary > 8000; ``` 上述例子展示了如何通过附加 where 子句来限制 count 所作用的对象集合,从而得到符合条件的具体实例个数[^2]。 #### 四、分组后的总计 除了单独求和之外,COUNT 还能够与其他 SQL 关键字如 GROUP BY 协作工作,以便按类别分别统计数据量: ```sql -- 获取各部门拥有的成员人数列表 SELECT department, COUNT(*) as member_counts FROM personnel GROUP BY department; ``` 这段代码片段说明了怎样依据部门名称来进行人员分布状况的小结报告生成过程[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值