数据库专题——深入理解count(*)为什么这么慢 Linux中MySQL数据库的使用④-----常用查询语句、常用函数 mysql备份与恢复:完全备份,增量备份,基于位置点恢复,基于时间点恢复 MySQL数据库的编译安装过程 《MySQL 入门教程》第 28 篇 字符集与排序规则 PHP面试技巧 之 职场暗语知多少?! [Dubox]实测。还是原来的配方,还是一样的味道! 【剑指金九银十】程序员,如何做到不惑?(附四面拿到字节跳动offer全过程) 超厉害的阿里技术读物,1500页超全计算机系统底层解析宝典 【融中财经早报9.16】大数据杀熟行为10月1日起明令禁止 大数据时代,机器学习算法该如何升级? 怎么判断自己是否适合做程序员 一分钟告诉你什么是区块链 一个时代一个机会,DeFi的起点X-DeFi,如何玩转X-DeFi? RTX3080显卡已被用于挖矿!映众辟谣:工程师测试散热 2020-09-15 比特币相当于房地产,怎样利用比特币获得流动现金? 区块链安全事件与代码审计 fisco bcos solidity销毁合约,删除合约的方法 Linux 中 Golang 的安装和环境配置 Golang interface{} 转换为某个结构体 区块链知识系列 - Raft 共识 OpenHarmony开发者文档开源计划,快快加入吧 融合创新提升服务,大数据搭建信息网 长三角税收一体化按下“快进键” 河钢集团与海尔集团签署物联网生态战略合作协议 1一个拥有万物互联神话,让我们看物联网是如何蓬勃发展的? 重庆大数据产业研究院成立,首批专家服务团名单公布 百分点大数据技术团队:互联网舆情系统的架构实践 水泥大数据研究院郑建辉:四季度水泥价格仍有望冲击去年高位 中国物联网与绿色智慧城市发展论坛召开 欧普照明点亮智慧道路之光 Android & Kotlin:Retrofit + Hilt 实现 看妹子app Android - 控件抖动效果 DevEco studio 一直加载gradle android如何获取调试版及发布版安全码SHA1 Android手机获取IP地址的两种方法 Android Activity 启动过程详解(上) 思维破局:挣钱其实没那么难,关键是方式要对 大数据赋能全产业链 为市民提供“一杯好奶” 运用大数据实现节能减排精准化 2020最新拼多多Java面试版,五面拿到28K的Offer 中国电信(安徽)大数据产业园落户南岗科技园 打造华东区域云计算领头羊 深度解读!阿里腾讯滴滴字节首选,新一代大数据引擎Flink厉害在哪?附学习礼包 网络编程5:socket服务端和客户端代码实现 微信小程序 蓝牙重连异常 errCode:10004,errMsg:notifyBLECharacteristicValueChange:fail setNot 蓝桥杯--第八届省赛试题-电子钟程序设计 【TCP回声服务器】一篇文章帮助你看懂TCP! 关于国标GB28181流媒体协议视频平台EasyGBS设备无法接入平台的问题排查 机器学习16 -- Lifelong Learning 终生学习 Vuex中发送mock请求返回数据 JS 正则表达式详解 学习笔记
您的位置:首页 >程序人生 >

数据库专题——深入理解count(*)为什么这么慢

深入理解count*为什么这么慢

不同存储引擎的实现方式InnoDB为什么不存起来MySQL的优化show tables status不准确

  曾经在依次面试中被问到过这么一个问题,假设开发一个交易平台过程中,有遇到过需要计算交易记录总数的情况该怎么办。可能大多数人的回答都是用select count(*) from t 不就搞定了吗 但是,面试官又问到随着系统中记录数越来越多,这条语句执行得越来越慢。那么为什么这么慢呢,今天我们就来聊一聊原因吧。

不同存储引擎的实现方式

 MySQL在不同的存储引擎中,count(*)的实现方式也不相同。

一般来说MyISAM引擎效率比较高,因为它是把一个表的总行数存到了磁盘上,因此执行count(*)的时候回直接返回计数值。但是如果加上where的话,MyISAM的表也不能反应这么快。InnoDB引擎它执行count(*)的时候比较麻烦,它需要把数据一行一行地从引擎里面读出来,然后再进行累计计数。

InnoDB为什么不存起来

 即使同一时刻的多个查询,由于多版本并发控制(MVCC)的原因,事务T启动的时候会创建一个视图read-view,InnoDB的表根据视图进行计数的。因此不能确定应该返回多少行。下面我们举个例子来解释一下:  假设表t1有5000条记录,三个用户并行的会话。

会话1先启动事务并查询一次表的总行数会话2先启动事务,插入一条记录后再查询表的总行数会话3先启动一个单独的语句,插入一条语句后再查询表的总行数。 会话1会话2会话3begin;select count(*) from t1;insert into t1 ()begin;insert into t1 ()select count(*) from t1(返回5000)select count(*) from t1(返回5002)select count(*) from t1(返回5001)

 最后,三个会话会同时查询表t1的总行数,但拿到的结果却不相同。这个原因其实和事务的设计有一定关系。一般默认隔离级别是可重复读(REPATABLE-READ) 在这里插入图片描述 而可重复读是通过MVCC来实现。每一行记录都要判断是否对这个会话可见。因此就count(*)来说,InnoDB只好把数据逐行地读出并判断,只有可见的行才能被用来计算表的总行数。

MySQL的优化

 MySQL实际上是做了优化的,InnoDB是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。因此普通索引树比主键索引树小很多。对于count(*)操作遍历哪棵树逻辑上来讲结果都是一样的。因此,为了遵循减少数据量遍历的原则,MySQL的优化器会找到最小的那颗树来进行遍历。   这里提到的主键索引树和普通索引树是什么意思?我们来举个例子: 假设有张InnoDB表t (id PK, name KEY, sex, flag) 表中有四条记录:

1, song, m, A

3, zhang, m, A

5, li, m, A

9, wang, f, B

 则它们的索引树如下图所示: 在这里插入图片描述

 假设要执行语句select * from t where name=’song’;

(1)首先在name普通索引上查询到PK=1;

(2)再在主键索引树上查询到(1,song, m, A)的行记录;

show tables status不准确

  其实MySQL有条命令show tables status命令执行结果中有条Rows能用于显示表有多少行,比如我们有张表结构是这样的 在这里插入图片描述  插入数据后,执行show table status命令结果如下: 在这里插入图片描述

 这条命令执行比count(* )快,那用它来代替count(*)岂不是很快。但是不行,为什么呢?  它不够准确,因为它的值是根据MySQL采样统计估算出来的,官方统计,误差还是可能会达到40%-50%。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。