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

导读

  • 在开发中一定会用到统计一张表的行数,比如一个交易系统,老板会让你每天生成一个报表,这些统计信息少不了sql中的count函数。
  • 但是随着记录越来越多,查询的速度会越来越慢,为什么会这样呢?Mysql内部到底是怎么处理的?
  • 今天这篇文章将从Mysql内部对于count函数是怎样处理的来展开详细的讲述。

count的实现方式

  • 在Mysql中的不同的存储引擎对count函数有不同的实现方式。
  • MyISAM引擎把一个表的总行数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率很高(没有where查询条件)。
  • InnoDB引擎并没有直接将总数存在磁盘上,在执行count(*)函数的时候需要一行一行的将数据读出来,然后累计总数。

为什么InnoDB不将总数存起来?

  • 说到InnoDB相信读者总会想到其支持事务的特性,事务具有隔离性,如果将总数存起来,怎么保证各个事务之间的总数的一致性呢?不明白的看下图:

a48e3e8c762d052bc814f3e4ad1b2826.png
  • 事务A事务B中的count(*)的执行结果是不同的,因此InnoDB引擎在每个事务中返回多少行是不确定的,只能一行一行的读出来用来判断总数。

如何提升count效率

  • InnoDB对于如何提升count(*)的查询效率,网上有多种解决办法,这里主要介绍三种,并分析可行性。

show table status

  • show table status这个命令能够很快的查询出数据库中每个表的行数,但是真的能够替代count(*)吗?
  • 答案是不能。原因很简单,这个命令统计出来的值是一个「估值」,因此是不准确的,官方文档说误差大概在40%-50%
  • 因此这种方法直接pass,不准确还用它干嘛。

缓存系统存储总数

  • 这种方法也是最容易想到的,增加一行就+1,删除一行就-1,并且缓存系统读取也是很快,既简单又方便的为什么不用?
  • 缓存系统和Mysql是两个系统,比如redisMysql这两个是典型的比较。两个系统最难的就是在高并发下无法保证数据的一致性。通过以下两图我们来理解一下:

35978d8fae0637dfdd53ee6738494455.png

78bfd363a111f13c057e50187dd10ec3.png
  • 通过上面两张图,无论是redis计数+1还是insert into user先执行,最终都会导致数据在逻辑上的不一致。第一张图会出现redis计数少了,第二张图虽然计数正确了但是并没有查询出插入的那一行数据。
  • 在并发系统里面,我们是无法精确控制不同线程的执行时刻的,因为存在图中的这种操作序列,所以,我们说即使Redis正常工作,这个计数值还是逻辑上不精确的。

在数据库保存计数

  • 通过缓存系统保存的分析得知了使用缓存无法保证数据在逻辑上的一致性,因此我们想到了直接使用数据库来保存,有了「事务」的支持,也就保证了数据的一致性了。
  • 如何使用呢?很简单,直接将计数保存在一张表中(table_name,total)。
  • 至于执行的逻辑只需要将缓存系统中redis计数+1改成total字段+1即可,如下图:

e40e484330c1f15c85d08e84ceb44331.png
  • 由于在同一个事务中,保证了数据在逻辑上的一致性。

不同count的用法

  • count()是一个聚合函数,对于返回的结果集,一行行地判断,如果count函数的参数不是NULL,累计值就加1,否则不加。最后返回累计值。
  • count的用法有多种,分别是count(*)、count(字段)、count(1)、count(主键id)。那么多种用法,到底有什么差别呢?当然,「前提是没有where条件语句」。
  • count(id):InnoDB引擎会遍历整张表,把每一行的id值都取出来,返回给server层。server层拿到id后,判断是不可能为空的,就按行累加。
  • count(1):InnoDB引擎遍历整张表,但不取值。server层对于返回的每一行,放一个数字1进去,判断是不可能为空的,按行累加。
  • count(字段):
  • 如果这个“字段”是定义为not null的话,一行行地从记录里面读出这个字段,判断不能为null,按行累加;
  • 如果这个字段定义允许为null,那么执行的时候,判断到有可能是null,还要把值取出来再判断一下,不是null才累加。
  • count(*):不会把全部字段取出来,而是专门做了优化,不取值。count(*)肯定不是null,按行累加。
  • 所以结论很简单:「按照效率排序的话,count(字段)<count(主键id)<count(1)≈count(*),所以建议读者,尽量使用count(*)。」
  • 「注意」:这里肯定有人会问,count(id)不是走的索引吗,为什么查询效率和其他的差不多呢?陈某在这里解释一下,虽然走的索引,但是还是要一行一行的扫描才能统计出来总数。

总结

  • MyISAM表虽然count(*)很快,但是不支持事务;
  • show table status命令虽然返回很快,但是不准确;
  • InnoDB直接count(*)会遍历全表(没有where条件),虽然结果准确,但会导致性能问题。
  • 缓存系统的存储计数虽然简单效率高,但是无法保证数据的一致性。
  • 数据库保存计数很简单,也能保证数据的一致性,建议使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/533679.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jmeter 高并发测试报告_JMeter分布式测试

一、为什么要使用分布式测试按照一般的压力机配置&#xff0c;jmeter的GUI模式下(Windows)&#xff0c;最多支持300左右的模拟请求线程&#xff0c;再大的话&#xff0c;容易造成卡顿、无响应等情况&#xff0c;这是限于jmeter其本身的机制和硬件配置。有时候为了尽量模拟业务场…

登陆拦截拦截ajax,过滤器实现登录拦截需要注意的问题(AJAX请求的处理)

1.问题描述&#xff1a;最近自己在写demo时遇到一个问题&#xff0c;在ajax请求时用Filter做登录拦截&#xff0c;结果页面不跳转(Ajax是不能做转发和重定向的)、、、、最终的最终在同事zt的提示下&#xff0c;恍然大悟&#xff0c;虽然很基本的问题&#xff0c;但也纠结了好久…

半圆阴影_六年级数学:怎么求阴影部分面积?正方形与半圆,割补法常考题

欢迎您来到方老师数学课堂&#xff0c;请点击上方蓝色字体&#xff0c;添加关注。所有的视频内容&#xff0c;全部免费&#xff0c;请大家放心关注&#xff0c;放心订阅。六年级数学&#xff1a;怎么求阴影部分面积&#xff1f;正方形与半圆&#xff0c;割补法常考题。大家先在…

c语言判断整数_用c++编写闰年的判断基础程序

其实c语言与c语言有太多共同的东西&#xff0c;学习过c语言再学习c语言就显得轻而易举。当然学过了c再去学习c语言也是有一些帮助的(但是个人不提倡先学习c在学c语言)。由于现在经常看见有关闰年的程序&#xff0c;风式各样&#xff0c;眼花缭乱&#xff0c;些许凌乱&#xff0…

cat日志 搜索_大日志,看我如何对付你

在服务器接口测试中&#xff0c;我们经常会和各种日志打交道。一旦测试时服务端出现了问题&#xff0c;而单凭服务端的日志又不能发现问题原因的时候&#xff0c;往往开发要向我们测试人员询问客户端这边的情况&#xff0c;希望看看我们能不能提供一些有用信息&#xff0c;如错…

python编译成dll文件_用vc生成可被python调用的dll文件

前提已经有.c 和.i文件 用swid编译了.i文件生成了wrap.c文件和.py文件 vc创建dll工程 将.h加入到头文件中.c文件和wrap.c文件添加到源文件中 将.i文件添加到工程目录下 Tools->Options->Directories中修改include 和lib 添加python里的include 和libs 把\libs\python27.l…

加载gif动图_GIF生成神器——ScreenToGif

每次需要做一个动图展示时&#xff0c;总是感觉很头疼。截图吧&#xff0c;需要的图片太多&#xff1b;录视频吧&#xff0c;文件太大&#xff1b;做动图吧&#xff0c;太麻烦。今天推荐的这个软件或许能够解决大家这个困惑&#xff0c;今天推荐的是动图生成神器——ScreenToGi…

vue底部选择器_vue实现动态显示与隐藏底部导航的方法分析

vue实现动态显示与隐藏底部导航的方法分析本文实例讲述了vue实现动态显示与隐藏底部导航的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;在日常项目中&#xff0c;总有几个页面是要用到底部导航的&#xff0c;总有那么些个页面&#xff0c;是不需要底部导航的&a…

java 修改最大nio连接数_关于java流的几个概念:IO、BIO、NIO、AIO,有几个人全知道?...

关于同步、阻塞的知识我之前的文章有介绍&#xff0c;所以关于流用到这些概念与之前多线程用的概念一样。下面具体来看看java中的几种流IO/BIOBIO就是指IO&#xff0c;即传统的Blocking IO,即同步并阻塞的IO。这也是jdk1.4之前的唯一选择&#xff0c;依赖于ServerSocket实现&am…

python神秘的魔法函数_python魔法函数

一、参考二、构造和初始化2.1 __new__在对象实例化过程中最先调用的方法是__new__, 该方法接收参数为类&#xff0c;然后将其他参数&#xff0c;传递给__init__, 该魔法函数比较少见&#xff0c;可以使用其&#xff0c;创建单例类; __new__方法是一个类方法&#xff0c;需要携带…

python扫雷 广度优先_广度优先搜索(BFS)解题总结

定义 广度优先搜索算法&#xff08;Breadth-First-Search&#xff09;&#xff0c;是一种图形搜索算法。 简单的说&#xff0c;BFS是从根节点开始&#xff0c;沿着树(图)的宽度遍历树(图)的节点。 如果所有节点均被访问&#xff0c;则算法中止。 BFS同样属于盲目搜索。 一般用队…

python默认参数陷阱_python默认参数陷阱

0|1陷阱&#xff1f;学过函数的人一定听说过函数的默认参数&#xff0c;关于函数的默认参数&#xff0c;请看以下的例子&#xff1a;def extendList(val, lst[]):lst.append(val)return lstlist1 extendList(10)list2 extendList(123, [])print(list1 %s % list1)print(list…

python裁剪图片并保存_python – 如何从图像中剪切轮廓并将其保存到新文件中

大家好,这是我的第一个问题所以请保持温和.我有一个计算机视觉领域的项目,我是新的,我会很感激一些帮助.我有一个pcb的图像,我的(首先)任务是从背景中切断电路板并将其保存到新文件.如果结果只是没有灰色背景的普通pcb,那就没问题了. 我到目前为止尝试的是,首先使用阈值将图像转…

opencv如何把一个矩阵不同列分离开_学习OPEN_CV

OpenCv中文论坛精华地址http://www.opencv.org.cn/index.php/User:Ollydbg23http://sivp.sourceforge.net/(sivp)一、基础操作1. 数据类型 数据结构了解图像相关&#xff1a;cvArr cvMat IplImage数据数组的维数&#xff0c; 与数据的通道数 见P46 (76)2. 常见的矩阵操作熟悉3…

python文件合并_用Python 将两个文件的内容合并成一个新的文件.

一个文件的内容是:IntroductiontoProgramming,NetworkingFundamentals,InternetworkingTechnologies,PlatformTechnologies,InformationTechnologyforUsers,ComputerForensics,Enterpr... 一个文件的内容是: Introduction to Programming, Networking Fundamentals, Internetwo…

flash代码_Flash如何对制作文件进行优化

对FLASH进行优化分为两方面&#xff0c;一方面是代码上的优化&#xff0c;主要是通过优化提高FLASH性能&#xff0c;降低CPU占用和内存使用。另一方面是资源的优化&#xff0c;这方面的优化是为了减小编译后的文件大小以及制作文件的大小&#xff0c;因为如果不进行相应的优化&…

潜流式湿地计算_人工湿地计算书

人工湿地计算书1、尾水提升泵房集水池基本参数集水池设计规模为30000m3/d&#xff0c;约折合1250m3/h&#xff0c;按水力停留时间HRT为0.25 h计&#xff0c;集水井有效容积应为312.5 m3&#xff0c;考虑到与污水厂原有排污管道相契合&#xff0c;集水设计尺寸为&#xff1a;LBH…

deepin系统转为windows_windows系统下安装深度系统deepin

前期准备DiskGenius(用来扩展分区)deepin-20-amd64.iso(深度系统镜像文件)相关文件下载首先下载安装时要用的工具&#xff0c;分别为:DiskGenius , UltraISODiskGenius是一款磁盘工具&#xff0c;创建系统分区。UltraISO是用来打开系统光盘镜像文件工具。Win8/8.1/10无需下载Ul…

c3等待加载样式 vue_Vue.js__简易加载等待动画

Vue.js__简易加载等待动画Vue实现为览或讲琐了过自系一读页围这就多网解元当维自加&#xff0c;加载动画的样式取自其他出处&#xff0c;侵直分调浏器代&#xff0c;刚求的一学础过功互有解小久宗点差维含数删。将Vue属性览或讲琐了过自系一读页围这就多网解元当维和方法复制到…

软件开发模型_QT开发(二十三)——软件开发流程

一、软件开发流程简介软件开发流程是通过一系列步骤保证软件产品的顺利完成&#xff0c;是软件产品在生命周期内的管理学。软件开发流程的本质是软件开发流程与具体技术无关&#xff0c;是开发团队必须遵守开的规则。二、常见软件开发流程模型常见的软件开发流程模型包括即兴模…