count(*) 的实现方式
你首先要明确的是,在不同的 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(*) 的实现方式相关推荐
- 在vue组件中使用vuex的state状态对象的5种方式
下面是store文件夹下的state.js和index.js内容 state.js //state.js const state = {headerBgOpacity:0,loginStatus:0, ...
- mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count
count(*)的实现方式 在不同的MySQL引擎中,count()有不同的实现方式 1. MyISAM引擎把一个表的总行数存在了磁盘上,因此执行count()的时候会直接返回这个数,效率很高: 2. ...
- dbgrideh 为什么只一行_Mysql性能优化:为什么count(*)这么慢?
导读 在开发中一定会用到统计一张表的行数,比如一个交易系统,老板会让你每天生成一个报表,这些统计信息少不了sql中的count函数. 但是随着记录越来越多,查询的速度会越来越慢,为什么会这样呢?Mys ...
- count返回0_MySQL实战 | 14 为什么count(*)越来越慢?
select count(*) 应该是一个比较常用的语句,用来统计记录行数. 但是,慢慢地你会发现,这个语句越来越慢了,为什么呢? count(*) 的实现方式 首先,我们来看下它的实现方式. MyS ...
- MySQL 中 count(*) 和 count(1) 有什么区别?哪个性能最好?
当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1).count(*).count(字段) 等. 到底哪种效 ...
- 谁说count(*) 性能最差,我需要跟你聊聊
摘要:当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1).count(*).count(字段) 等.到底哪 ...
- select count(*) from返回值_MySQL 优化:count(1)真的比count(*)快吗
在实际项目开发中一定会有统计记录数的需求,比如统计用户数,像一些电商系统后台首页会统计订单量.上架商品数量等等,涉及到统计就离不开聚合函数 count() ,开发中常用写法如下: select cou ...
- oracle remap语句格式,impdp 中的remap方式
impdp 中的remap方式 impdp 中要是没有remap方式,那么个人认为datapump 将是一个死板的工具. remap_table方式 语法格式:REMAP_TABLE=[schema. ...
- mysql数据库中count的作用_MySQL数据库中的count的用法
1.概念 在开发系统的时候,可能经常需要计算一个表的行数,比如一个交易系统的所有变更记录总数.这时候你可能会想,一条select count(*) from t 语句不就解决了吗? 但是,会发现随着系 ...
最新文章
- MySQL安装查看密码修改密码
- C++的IO流的函数
- MVC,MVP,MVVM设计模式的比较
- vs2015安装与单元测试以及经过优化的算法
- airtest自动化测试_【游戏职业说】我在网易做测试开发(QA)
- HttpURLConnection与 HttpClient 区别/性能测试对比
- SAP License:作业类型作为成本对象
- html怎么只操作第一个li,css3如何选择第一个子元素?
- UnityShader2:Shader与材质
- 用例图分析---学生成绩管理系统
- RFID的无线通信原理
- 餐饮业实施5S管理的效益及实施方案
- flink不等于符号问题
- Servlet(互联网通信基础及实例)(上)
- Erlang之ETS,DETS入门
- Poj P3322 Bloxorz___bfs
- 原生HTML:img 相关属性详解(alt属性,onerror事件,以及其他基本属性),css中的object-fit
- 万兆电口网卡性能分析
- 中英三校合作开发新电池结构,可用于改善可穿戴设备体验
- 制造业ERP系统如何帮助企业做好生产物料管控?
热门文章
- python3 自定义排序_Python3中的自定义排序
- 中点击按钮新建widget_如何在iOS14中创建堆叠小组件?
- windows bat脚本编写_怎样在 txt 中用 2 行代码写出一个锁屏休息提醒脚本?
- android 多图片优化工具,总结Android App内存优化之图片优化
- 网卡设置 多网卡的7种bond模式原理
- Python实现温度转换
- extract进程 oracle,OracleGoldenGate系列:Extract进程的恢复原理
- 小苹果 html,定时轮播.html
- dataguard如何实现切换_ORACLE dataguard 切换
- js 冒泡排序_JS 里的简易算法和数据结构之复杂度