面试官:请说一下Mysql中count(1)、count(*)以及count(列)的区别?

这篇具有很好参考价值的文章主要介绍了面试官:请说一下Mysql中count(1)、count(*)以及count(列)的区别?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

近期在Review项目代码时,发现同事们在查询MySQL行数时存在多样的方式,有的使用COUNT(1), 有的用COUNT(id), 还有人选择了COUNT(*)。这混杂的选择引发了我的思考。当然这三种count的方式也是众说纷纭,其中最大的分歧点就是COUNT(*)COUNT(1)查询性能上,有人觉得COUNT(*)需要转换为COUNT(1),所以COUNT(1)得速度更快。究竟这三种计数方式之间有何区别,它们的背后原理是怎样的呢?

COUNT()含义

在《高性能Mysql》一书第236页中是这么解释COUNT的作用的:

COUNT()是一个特殊的函数,有两种非常不同的作用:它可以统计某个列值的数量,也可以统计行数。在统计列值时要求列值是非空的(不统计NULL)。如果在COUNT()的括号中指定了列或者列的表达式,则统计的就是这个表达式有值的结果数”。因为很多人对 NULL理解有问题,所以这里很容易产生误解。
COUNT()的另一个作用是统计结果集的行数。当MySOL确认括号内的表达式值不可能为空时,实际上就是在统计行数。最简单的就是当我们使用COUNT()的时候,这种情况下通配符并不会像我们猜想的那样扩展成所有的列,实际上,它会忽略所有的列而直接统计所有的行数。
我们发现一个最常见的错误就是,在括号内指定了一个列却希望统计结果集的行数。如果希望知道的是结果集的行数,最好使用COUNT(*),这样写意义清晰,性能也会很好

由此我们也可以大概总结COUNT函数的种方式如下:

  • COUNT(1): 此查询返回的是结果集中的行数,不关心具体的列内容,因此使用常数1。
    在很多数据库系统中,这种方式被优化为与 SELECT COUNT(*) 相同的性能水平,因为数据库引擎通常忽略括号内的内容。

  • COUNT(*):统计整个表的行数,不考虑是否有NULL值。
    通常优于 COUNT(id),因为它不需要关心具体的列,且现代数据库引擎会对其进行特殊优化。

  • COUNT(列) :统计指定列非空值的数量。需要考虑是否有NULL值
    此种方式取决于列是否有索引。如果 列有索引,数据库引擎可能会利用索引进行快速计数。如果没有索引,或者有大量NULL值,性能可能较差,因为需要扫描整个表。

区别

1、Mysql5.7

在MySql 5.7官方文档中是这么介绍COUNT(expr)函数的

COUNT(expr)
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.
If there are no matching rows, COUNT() returns 0.
mysql> SELECT student.student_name,COUNT(*)
FROM student,course
WHERE student.student_id=course.student_id
GROUP BY student_name;
COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values.

For transactional storage engines such as InnoDB, storing an exact row count is problematic. Multiple transactions may be occurring at the same time, each of which may affect the count.

InnoDB does not keep an internal count of rows in a table because concurrent transactions might “see” different numbers of rows at the same time. Consequently, SELECT COUNT(*) statements only count rows visible to the current transaction.

Prior to MySQL 5.7.18, InnoDB processes SELECT COUNT(*) statements by scanning the clustered index. As of MySQL 5.7.18, InnoDB processes SELECT COUNT(*) statements by traversing the smallest available secondary index unless an index or optimizer hint directs the optimizer to use a different index. If a secondary index is not present, the clustered index is scanned.

Processing SELECT COUNT(*) statements takes some time if index records are not entirely in the buffer pool. For a faster count, create a counter table and let your application update it according to the inserts and deletes it does. However, this method may not scale well in situations where thousands of concurrent transactions are initiating updates to the same counter table. If an approximate row count is sufficient, use SHOW TABLE STATUS.

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

For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. For example:
mysql> SELECT COUNT(*) FROM student;
This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT NULL.

从官方文档中我们可以看出mysql官方对COUNT函数的解释:

  • COUNT(expr) 返回由 SELECT 语句检索的行中 expr 的非 NULL 值的数量,结果为 BIGINT 值。如果没有匹配的行,COUNT() 返回 0。

  • COUNT(*) 有所不同,它返回所检索的行数的计数,无论它们是否包含 NULL 值。

  • 对于事务性存储引擎(如 InnoDB),存储准确的行数是有问题的。因为多个事务可能同时影响计数,InnoDB 不会保留表中行的内部计数。SELECT COUNT(*) 只会计算当前事务可见的行。

  • 在 MySQL 5.7.18 之前,InnoDB 通过扫描聚集索引处理 SELECT COUNT(*) 语句。从 MySQL 5.7.18 开始,除非索引或优化器提示指示使用其他索引,InnoDB 会通过遍历最小的可用二级索引来处理 SELECT COUNT(*) 语句。如果没有二级索引,则将扫描聚集索引。

  • 处理 SELECT COUNT(*) 语句可能花费一些时间,如果索引记录没有完全在缓冲池中。为了更快的计数,可以创建一个计数器表,并根据插入和删除操作进行更新。然而,在成千上万的并发事务更新同一计数器表的情况下,该方法可能无法很好地扩展。如果粗略的行数足够,可以使用SHOW TABLE STATUS

  • InnoDB 处理 SELECT COUNT(*)SELECT COUNT(1) 操作的方式相同,没有性能差异。

  • 对于 MyISAM 表,COUNT(\*) 在从一个表中检索、没有检索其他列、没有 WHERE 子句的情况下可以快速返回,因为 MyISAM 存储了准确的行数。COUNT(1) 只有在第一列被定义为 NOT NULL 时才能进行相同的优化。

2、Mysql 8.0

在Mysql8.0的文档中对COUNT(expr)的解释是这样

COUNT(expr) [over_clause]

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.

If there are no matching rows, COUNT() returns 0.COUNT(NULL)returns 0.

This function executes as a window function if over_clause is present. over_clause is as described in Section 12.20.2, “Window Function Concepts and Syntax”.

mysql> SELECT student.student_name,COUNT(*) FROM student,course WHERE student.student_id=course.student_id GROUP BY student_name;
COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values.

For transactional storage engines such as InnoDB, storing an exact row count is problematic. Multiple transactions may be occurring at the same time, each of which may affect the count.

InnoDB does not keep an internal count of rows in a table because concurrent transactions might “see” different numbers of rows at the same time. Consequently, SELECT COUNT(*) statements only count rows visible to the current transaction.

As of MySQL 8.0.13, SELECT COUNT(*) FROM tbl_name query performance for InnoDB tables is optimized for single-threaded workloads if there are no extra clauses such as WHERE or GROUP BY.

InnoDB processes SELECT COUNT(*) statements by traversing the smallest available secondary index unless an index or optimizer hint directs the optimizer to use a different index. If a secondary index is not present, InnoDB processes SELECT COUNT(*) statements by scanning the clustered index.

Processing SELECT COUNT(*) statements takes some time if index records are not entirely in the buffer pool. For a faster count, create a counter table and let your application update it according to the inserts and deletes it does. However, this method may not scale well in situations where thousands of concurrent transactions are initiating updates to the same counter table. If an approximate row count is sufficient, use SHOW TABLE STATUS.

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

For MyISAM tables, COUNT(*)is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. For example:

mysql> SELECT COUNT(*) FROM student;
This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT NULL.

从mysql8.0的文档中我们可以看出mysql8.0对COUNT的解释

  • COUNT(expr) 返回在由 SELECT 语句检索的行中 _expr_ 的非 NULL 值的数量,结果为 BIGINT 值。如果没有匹配的行,COUNT() 返回 0。COUNT(NULL) 也返回 0。

  • COUNT(*) 有所不同,它返回所检索的行数的计数,无论它们是否包含 NULL 值。

  • 对于事务性存储引擎(如 InnoDB),存储准确的行数是有问题的,因为多个事务可能同时影响计数。InnoDB 不会保留表中行的内部计数。SELECT COUNT(*) 只计算当前事务可见的行。

  • 在 MySQL 8.0.13 及以后版本,对于 InnoDB 表,执行 SELECT COUNT(*) FROM tbl_name 查询性能在没有额外子句(如 WHERE 或 GROUP BY)的情况下进行了优化,特别适用于单线程工作负载。

  • InnoDB 处理 SELECT COUNT(*) 语句的方式:

    • 通过遍历最小可用二级索引,除非指示使用其他索引。
    • 如果没有二级索引,InnoDB 通过扫描聚集索引来处理 SELECT COUNT(*) 语句。
  • 处理 SELECT COUNT(*) 语句可能花费一些时间,如果索引记录没有完全在缓冲池中。为了更快的计数,可以创建一个计数器表,让应用程序根据插入和删除操作进行更新。但是,这种方法在数千个并发事务同时对同一计数器表进行更新的情况下可能不会很好地扩展。如果粗略的行数足够,可以使用 SHOW TABLE STATUS

  • InnoDB 对待 SELECT COUNT(*)SELECT COUNT(1) 操作的方式相同,没有性能差异。

  • 对于 MyISAM 表,COUNT(*) 在从一个表中检索、没有检索其他列、没有 WHERE 子句的情况下可以快速返回,因为 MyISAM 存储了准确的行数。COUNT(1) 只有在第一列被定义为 NOT NULL 时才能进行相同的优化。

结合Mysql5.7与Mysql8.0的文档我们可以看出两个版本对COUNT的支持的差异:

  • MySQL 8.0 优化了 InnoDB 表的 SELECT COUNT(*) 查询性能: 在 MySQL 8.0.13 及以后版本,对于 InnoDB 表,执行 SELECT COUNT(*) 查询的性能进行了优化,特别适用于单线程工作负载。这是 MySQL 5.7 文档中未包含的新特性。
  • MyISAM 表的优化说明:
    MySQL 8.0 文档中强调了 MyISAM 表在执行 COUNT(*) 时的优化情况,即在从一个表中检索、没有检索其他列、没有 WHERE 子句的情况下可以快速返回。MySQL 5.7 文档中也提到了 MyISAM 表的优化,但对于 COUNT(*) 的具体优化情况没有细节。

MySQL 8.0 在性能优化方面对于 InnoDB 表的 SELECT COUNT(*) 查询进行了特别的关注,而且在 MyISAM 表的优化方面进行了详细的说明。其他方面,两个版本在COUNT()函数的解释和使用上基本保持一致。

基于此我们明白,其实COUNT(*)COUNT(1)其实是一样的,在性能上并没有差异。

那这两种方式与COUNT(列)的差异呢?从以上《高性能Mysql》以及Mysql官方文档中我们知道,COUNT(列)是统计非空列的行数,它也会遍历整张表,然后会对列对应的值做非空判断,非空的字段进行个数累加。当然这是列为主键索引时的操作。如果列不为主键索引时,那么查询时还需要进行回表操作,再根据主键获取数据,此时无疑是增加了一次IO,在性能上其实是不如COUNT(*)COUNT(1)的。那么我们就可以知道,按照效率来看,count(*) = count(1) > count(主键) > count(非主键列)

使用建议

  • 如果你想知道一张表的大概行数,我们可以直接使用show table status命令或者咱们使用的一些mysql客户端Navicat或者datagrip都可以办到。

  • 如果你想获取一张表的确切行数时,我可以是优先使用使用 COUNT(*) 获取行数,这样写法清晰,性能较好,尤其对于 InnoDB 表的优化更为明显。我们要避免使用 COUNT(列) 统计行数,除非你真的需要统计该列非空值的数量,否则容易产生误解。

篇幅有限,深入验证将在后续文章中介绍。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等文章来源地址https://www.toymoban.com/news/detail-825185.html

到了这里,关于面试官:请说一下Mysql中count(1)、count(*)以及count(列)的区别?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 简述一下cookie、session以及token的区别

    相同都是用来签权服务器的,不同的是主要是存储位置和存储容量 cookie数据存放在客户的浏览器上、session数据放在服务器内存上、token存储在服务器数据库上 cookie 单个4kb,不超过20个;session不限制 token是接口测试时鉴权码,其实也就是一个字符串,一般情况下登陆后才可以

    2024年04月14日
    浏览(41)
  • 面试题:简单说一下阻塞IO、非阻塞IO、IO复用的区别 ?

    在《Unix网络编程》一书中提到了五种IO模型,分别是:阻塞IO、非阻塞IO、IO复用、信号驱动IO以及异步IO。本篇文章主要介绍IO的基本概念以及阻塞IO、非阻塞IO、IO复用三种模型,供大家参考学习。 计算机视角理解IO: 对于计算机而言,任何涉及到计算机核心(CPU和内存)与其

    2024年01月22日
    浏览(39)
  • 盘点一下PostgreSQL和MySQL的区别点

    上期有说,数据环境切换,由MySQL换成PostgreSQL。 那么为了大家以后少踩坑,简单总结了下我曾踩过的坑和需要注意的点。 首先PostgreSQL有一个模式的概念。 一、格式区别: 和Oracle一样,PostgreSQL也是严格区分大小写。 二、符号区别: 和Oracle一样PostgreSQL中,\\\" \\\" 双引号是区分库

    2024年02月05日
    浏览(32)
  • 【面试题】MySQL 事务的四大特性说一下?

    事务是一个或多个 SQL 语句组成的一个执行单元,这些 SQL 语句要么全部执行成功,要么全部不执行,不会出现部分执行的情况。事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。 事务的主要作用是保证数据库操作的一致性,即事务内的

    2024年04月22日
    浏览(33)
  • SQL server 与 MySQL count函数、以及sum、avg 是否包含 为null的值

    sql server 与 mysql count 作用一样。 count 计算指定字段出现的个数, 不是计算 null的值 获取表的条数 count(n) n:常数 count(1),count(0)等 count(*) count(字段) 其中字段为null 不会统计在内。 avg(字段)、sum(字段) 跟count(字段) 一样 不统计字段为null的。

    2024年02月14日
    浏览(50)
  • mybatis&Mysql分页查询,以及SQL_CALC_FOUND_ROWS与count(*) 性能对比

    温故而知新,这里记录一下         分页查询每个人程序猿几乎都使用过,但是有部分同学不懂什么是物理分页和逻辑分页。         相当于执行了limit分页语句,返回部分数据。物理分页只返回部分数据占用内存小,能够获取数据库最新的状态,实施性比较强,一般

    2024年01月23日
    浏览(54)
  • 面试官:MySQL 到底是 join 性能好,还是 in 一下更快呢?被问懵逼了…

    来源:https://juejin.cn/post/7169567387527282701 先总结: 数据量小的时候,用join更划算 数据量大的时候,join的成本更高,但相对来说join的速度会更快 数据量过大的时候,in的数据量过多,会有无法执行SQL的问题,待解决 事情是这样的,去年入职的新公司,之后在代码review的时候被

    2024年02月04日
    浏览(39)
  • 近期学员遇到的软件测试面试真题

    本期由耳朵鹅小姐姐提供,题目将收录到woqurefan.cn测试面试题库。 问题1: 可以转语言么?之前学的java,转成python 这种。你觉得能胜任么? 回答: 表面先回答可以,稳住面试官,看他接下来说什么。实际上自己可能不可以,毕竟转语言的代价和成本都不低,而且一旦转成更

    2023年04月08日
    浏览(50)
  • 4. count(*) 、count(1) 、count(字段) 区别

    哪种 count 性能最好? count(*) = count(1) count(字段) count( ) 是什么? count() 是一个聚合函数,函数的参数不仅可以是字段名,也可以是其他任意表达式,该函数作用是 统计符合查询条件的记录中,函数指定的参数不为 NULL 的记录有多少个 。 count(*)、 count(1) 都是检索表中所有记

    2024年02月11日
    浏览(36)
  • count(0)、count(1)和count(*)、count(列名) 的区别

    当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1)、count( * )、count(字段) 等。 到底哪种效率是最好的呢?是不是 count( * ) 效率最差? 一. 哪种 count 性能最好? 哪种 count 性能最好? 我先直接说结论

    2024年02月08日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包