你首先要明确的是,在不同的 MySQL 引擎中,count(*) 有不同的实现方式。

MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高;

InnoDB 引擎就麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数

这里需要注意的是,我们在这篇文章里讨论的是没有过滤条件的 count(*),如果加了 where 条件的话,MyISAM 表也是不能返回得这么快的。

在前面的文章中,我们一起分析了为什么要使用 InnoDB,因为不论是在事务支持、并发能力还是在数据安全方面,InnoDB 都优于 MyISAM。我猜你的表也一定是用了 InnoDB 引擎。这就是当你的记录数越来越多的时候,计算一个表的总行数会越来越慢的原因。

为什么 InnoDB 不跟 MyISAM 一样,也把数字存起来呢?

这是因为即使是在同一个时刻的多个查询,由于多版本并发控制(MVCC)的原因,InnoDB 表“应该返回多少行”也是不确定的。这里,我用一个算 count(*) 的例子来为你解释一下。

假设表 t 中现在有 10000 条记录,我们设计了三个用户并行的会话。

会话 A 先启动事务并查询一次表的总行数;
会话 B 启动事务,插入一行后记录后,查询表的总行数;
会话 C 先启动一个单独的语句,插入一行记录后,查询表的总行数。

我们假设从上到下是按照时间顺序执行的,同一行语句是在同一时刻执行的。

你会看到,在最后一个时刻,三个会话 A、B、C 会同时查询表 t 的总行数,但拿到的结果却不同。

这和 InnoDB 的事务设计有关系,可重复读是它默认的隔离级别,在代码上就是通过多版本并发控制,也就是 MVCC 来实现的。每一行记录都要判断自己是否对这个会话可见,因此对于 count(*) 请求来说,InnoDB 只好把数据一行一行地读出依次判断,可见的行才能够用于计算“基于这个查询”的表的总行数

当然,现在这个看上去笨笨的 MySQL,在执行 count(*) 操作的时候还是做了优化的。

你知道的,InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。所以,普通索引树比主键索引树小很多。对于 count(*) 这样的操作,遍历哪个索引树得到的结果逻辑上都是一样的。因此,MySQL 优化器会找到最小的那棵树来遍历。在保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。

如果你用过 show table status 命令的话,就会发现这个命令的输出结果里面也有一个 TABLE_ROWS 用于显示这个表当前有多少行,这个命令执行挺快的,那这个 TABLE_ROWS 能代替 count(*) 吗?

你可能还记得在第 10 篇文章《 MySQL 为什么有时候会选错索引?》中我提到过,索引统计的值是通过采样来估算的。实际上,TABLE_ROWS 就是从这个采样估算得来的,因此它也很不准。有多不准呢,官方文档说误差可能达到 40% 到 50%。所以,show table status 命令显示的行数也不能直接使用。

到这里我们小结一下:

MyISAM 表虽然 count(*) 很快,但是不支持事务;
show table status 命令虽然返回很快,但是不准确;
InnoDB 表直接 count(*) 会遍历全表,虽然结果准确,但会导致性能问题。

思考

- 如何加速InnoDB count(*) 的速度?

count(*) 的实现方式相关推荐

  1. 在vue组件中使用vuex的state状态对象的5种方式

    下面是store文件夹下的state.js和index.js内容 state.js //state.js const state = {headerBgOpacity:0,loginStatus:0, ...

  2. mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count

    count(*)的实现方式 在不同的MySQL引擎中,count()有不同的实现方式 1. MyISAM引擎把一个表的总行数存在了磁盘上,因此执行count()的时候会直接返回这个数,效率很高: 2. ...

  3. dbgrideh 为什么只一行_Mysql性能优化:为什么count(*)这么慢?

    导读 在开发中一定会用到统计一张表的行数,比如一个交易系统,老板会让你每天生成一个报表,这些统计信息少不了sql中的count函数. 但是随着记录越来越多,查询的速度会越来越慢,为什么会这样呢?Mys ...

  4. count返回0_MySQL实战 | 14 为什么count(*)越来越慢?

    select count(*) 应该是一个比较常用的语句,用来统计记录行数. 但是,慢慢地你会发现,这个语句越来越慢了,为什么呢? count(*) 的实现方式 首先,我们来看下它的实现方式. MyS ...

  5. MySQL 中 count(*) 和 count(1) 有什么区别?哪个性能最好?

    当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1).count(*).count(字段) 等. 到底哪种效 ...

  6. 谁说count(*) 性能最差,我需要跟你聊聊

    摘要:当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1).count(*).count(字段) 等.到底哪 ...

  7. select count(*) from返回值_MySQL 优化:count(1)真的比count(*)快吗

    在实际项目开发中一定会有统计记录数的需求,比如统计用户数,像一些电商系统后台首页会统计订单量.上架商品数量等等,涉及到统计就离不开聚合函数 count() ,开发中常用写法如下: select cou ...

  8. oracle remap语句格式,impdp 中的remap方式

    impdp 中的remap方式 impdp 中要是没有remap方式,那么个人认为datapump 将是一个死板的工具. remap_table方式 语法格式:REMAP_TABLE=[schema. ...

  9. mysql数据库中count的作用_MySQL数据库中的count的用法

    1.概念 在开发系统的时候,可能经常需要计算一个表的行数,比如一个交易系统的所有变更记录总数.这时候你可能会想,一条select count(*) from t 语句不就解决了吗? 但是,会发现随着系 ...

最新文章

  1. MySQL安装查看密码修改密码
  2. C++的IO流的函数
  3. MVC,MVP,MVVM设计模式的比较
  4. vs2015安装与单元测试以及经过优化的算法
  5. airtest自动化测试_【游戏职业说】我在网易做测试开发(QA)
  6. HttpURLConnection与 HttpClient 区别/性能测试对比
  7. SAP License:作业类型作为成本对象
  8. html怎么只操作第一个li,css3如何选择第一个子元素?
  9. UnityShader2:Shader与材质
  10. 用例图分析---学生成绩管理系统
  11. RFID的无线通信原理
  12. 餐饮业实施5S管理的效益及实施方案
  13. flink不等于符号问题
  14. Servlet(互联网通信基础及实例)(上)
  15. Erlang之ETS,DETS入门
  16. Poj P3322 Bloxorz___bfs
  17. 原生HTML:img 相关属性详解(alt属性,onerror事件,以及其他基本属性),css中的object-fit
  18. 万兆电口网卡性能分析
  19. 中英三校合作开发新电池结构,可用于改善可穿戴设备体验
  20. 制造业ERP系统如何帮助企业做好生产物料管控?

热门文章

  1. python3 自定义排序_Python3中的自定义排序
  2. 中点击按钮新建widget_如何在iOS14中创建堆叠小组件?
  3. windows bat脚本编写_怎样在 txt 中用 2 行代码写出一个锁屏休息提醒脚本?
  4. android 多图片优化工具,总结Android App内存优化之图片优化
  5. 网卡设置 多网卡的7种bond模式原理
  6. Python实现温度转换
  7. extract进程 oracle,OracleGoldenGate系列:Extract进程的恢复原理
  8. 小苹果 html,定时轮播.html
  9. dataguard如何实现切换_ORACLE dataguard 切换
  10. js 冒泡排序_JS 里的简易算法和数据结构之复杂度