关系经济人类预测化学自然
自然科学
知识物理
化学生物
地理解释
预测理解
本质社会
人类现象
行为研究
经济政治
心理结构
关系指导
人文遗产

深入理解selectcount()

5月1日 满月族投稿
  深入理解selectcount()底层究竟做了什么
  2019061112:58Java技术架构
  专注于Java领域优质技术,欢迎关注
  作者:贾春生
  SELECTCOUNT()FROMt是个再常见不过的SQL需求了。在MySQL的使用规范中,我们一般使用事务引擎InnoDB作为(一般业务)表的存储引擎,在此前提下,COUNT()操作的时间复杂度为O(N),其中N为表的行数。
  而MyISAM表中可以快速取到表的行数。这些实践经验的背后是怎样的机制,以及为什么需要可以是这样,就是此文想要探讨的。
  先来看一下概况:MySQLCOUNT()在2种存储引擎中的部分问题:
  下面就带着这些问题,以InnoDB存储引擎为主来进行讨论。一、InnoDB全表COUNT()
  主要问题:执行过程是怎样的?如何计算count?影响count结果的因素有哪些?count值存在哪里?涉及的数据结构是怎样的?为什么InnoDB只能通过扫表来实现count()?(见本文最后的问题)全表COUNT()作为tablescan类型操作的一个case,有什么风险?COUNT()操作是否会像SELECT一样可能读取大字段涉及的溢出页?
  1。执行框架循环:读取计数
  1。1基本结论全表扫描,一个循环解决问题。循环内:先读取一行,再决定该行是否计入count。循环内是一行一行进行计数处理的。
  1。2说明
  简单SELELCTSQL的执行框架,类比INSERTINTOSELECT是同样的过程。
  下面会逐步细化如何读取与计数(count)。
  2。执行过程
  引述:执行过程部分,分为4个部分:COUNT()前置流程:从Client端发SQL语句,到MySQLServer端执行SELECT之前,为后面的一些阐述做一铺垫。COUNT()流程:简要给出代码层面的流程框架及2个核心步骤的重点调用栈部分。读取一行:可见性及rowsearchmvcc函数,介绍可见性如何影响COUNT()结果。计数一行:Evaluatejoinrecord与列是否为空,介绍计数过程如何影响COUNT()结果。
  如果读者希望直接看如何进行COUNT(),那么也可以忽略(1),而直接跳到(2)开始看。
  2。1COUNT()前置流程回忆从Client端发SQL到subselect函数
  为了使看到的调用过程不太突兀,我们还是先回忆一下如何执行到subselect函数这来的:
  1。MySQLClient端发送SQL语句,根据MySQL通信协议封包发送。
  2。MysqlServer端接收数据包,由协议解析出command类型(QUERY)及SQL语句(字符串)。
  3。SQL语句经过解析器解析输出为JOIN类的对象,用于结构化地表达该SQL语句。PS:这里的JOIN结构,不仅仅是纯语法结构,而是已经进行了语义处理,粗略地说,汇总了表的列表(tablelist)、目标列的列表(targetlist)、WHERE条件、子查询等语法结构。在全表COUNT()case中,tablelist〔表t(别名也是t)〕,targetlist〔目标列对象(列名为COUNT())〕,当然这里没有WHERE条件、子查询等结构。
  4。JOIN对象有2个重要的方法:JOIN::optimize(),JOIN::exec(),分别用于进行查询语句的优化和查询语句的执行。
  joinoptimize(),优化阶段(稍后myisam下全表count()操作会涉及这里的一点内容)。
  joinexec(),执行阶段(重点),包含了InnoDB下全表count()操作的执行流程。
  5。joinexec()经过若干调用,将调用到subselect函数来执行简单SQL,包括COUNT()。
  6。ENDofsubselect。
  2。2COUNT()流程(于subselect函数中)
  上层的流程与代码是比较简单的,集中在subselect函数中,其中2类函数分别对应于前面执行框架部分所述的2个步骤读取、计数。先给出结论如下:读取一行:从相对顶层的subselect函数经过一番调用,最终所有分支将调用到rowsearchmvcc函数中,该函数就是用于从InnoDB存储引擎所存储的Btree结构中读取一行到内存中的一个buf(uchar)中,待后续处理使用。这里会涉及行锁的获取、MVCC及行可见性的问题。当然对于SELECTCOUNT()这类快照读而言,只会涉及MVCC及其可见性,而不涉及行锁。详情可跳至可见性与rowsearchmvcc函数部分。计数一行:代码层面,将会在evaluatejoinrecord函数中对所读取的行进行评估,看其是否应当计入count中(即是否要count)。
  简单来说,COUNT(arg)本身为MySQL的函数操作,对于一行来说,若括号内的参数arg(某列或整行)的值若不是NULL,则count,否则对该行不予计数。详情可跳至Evaluatejoinrecord与列是否为空部分。
  这两个阶段对COUNT()结果的影响如下:(两层过滤)
  SQL层流程框架相关代码摘要如下:
  Q:代码层面,第一步骤(读取一行)有2个分支,为什么?
  A:从InnoDB接口层面考虑,分为读第一行和读下一行,是2个不同的执行过程,读第一行需要找到一个(cursor)位置并做一些初始化工作让后续的过程可递归。
  正如我们如果用脚本程序来进行逐行的扫表操作,实现上就会涉及下面2个SQL:SELECTidFROMtLIMIT1;ORSELECTMIN(id)1FROMt;lastidSELECTidFROMtWHEREidlastidLIMIT1;
  具体涉及到此例的代码,SQL层到存储引擎层的调用关系,读取阶段的调用栈如下:(供参考)
  我们可以看到,无论是哪一个分支的读取,最终都殊途同归于rowsearchmvcc函数。
  以上是对LOOP中的代码做一些简要的说明,下面来看rowsearchmvcc与evaluatejoinrecord如何输出最终的count结果。
  2。3行可见性及rowsearchmvcc函数
  这里我们主要通过一组case和几个问题来看行可见性对COUNT()的影响。
  Q:对于SELECTCOUNT()FROMt或者SELECTMIN(id)FROMt操作,第一次的读行操作读到的是表t中(B树最左叶节点page内)的最小记录吗?(haindexfirst为何也调用rowsearchmvcc来获取最小key值?)
  A:不一定。即使是MIN(id)也不一定就读取的是id最小的那一行,因为也同样有行可见性的问题,实际上indexread取到的是当前事务内语句可见的最小index记录。这也反映了前面提到的joinreadfirst与joinreadnext殊途同归到rowsearchmvcc是理所应当的。
  Q:针对图中最后一问,如果事务X是RU(ReadUncommitted)隔离级别,且CInsert(100)的完成是在Xcount()执行过程中(仅扫描到5或10这条记录)完成的,那么Xcount()在事务CInsert(100)完成后,能否在之后的读取过程中看到100这条记录呢?
  A:MySQL采取读到什么就是什么的策略,即Xcount()在后面可以读到100这条记录。
  2。4evaluatejoinrecord与列是否为空
  Q:某一行如何计入count?
  A:两种情况会将所读的行计入count:
  1、如果COUNT函数中的参数是某列,则会判断所读行中该列定义是否Nullable以及该列的值是否为NULL;若两者均为是,则不会计入count,否则将计入count。e。g。SELECTCOUNT(colname)FROMtcolname可以是主键、唯一键、非唯一键、非索引字段
  2、如果COUNT中带有,则会判断这部分的整行是否为NULL,如果判断参数为NULL,则忽略该行,否则count。e。g1。SELECTCOUNT()FROMte。g2。SELECTCOUNT(B。)FROMALEFTJOINBONA。idB。id
  Q:特别地,对于SELECTCOUNT(id)FROMt,其中id字段是表t的主键,则如何?
  A:效果上等价于COUNT()。因为无论是COUNT(),还是COUNT(pkcol)都是因为有主键从而充分断定索取数据不为NULL,这类COUNT表达式可以用于获取当前可见的表行数。
  Q:用户层面对InnoDBCOUNT()的优化操作问题
  A:这个问题是业界熟悉的一个问题,扫描非空唯一键可得到表行数,但所涉及的字节数可能会少很多(在表的行长与主键、唯一键的长度相差较多时),相对的IO代价小很多。
  相关调用栈参考如下:
  二、数据结构:
  Q:count值存储在哪个内存变量里?
  A:SQL解析后,存储于表达COUNT()这一项中,((Itemsumcount)itemsum)count
  如下图所示回顾我们之前COUNT()前置流程部分提到的JOIN结构。
  即SQL解析器为每个SQL语句进行结构化,将其放在一个JOIN对象(join)中来表达。在该对象中创建并填充了一个列表resultfieldlist用于存放结果列,列表中每个元素则是一个结果列的(Itemresultfield)对象(指针)。
  在COUNT()case中,结果列列表只包含一个元素,(Itemsumcount:publicItemresultfield)类型对象(nameCOUNT()),其中该类所特有的成员变量count即为所求。三、MyISAM全表COUNT()
  由于MyISAM引擎并不常用于实际业务中,仅做简要描述如下:MyISAMCOUNT()操作是O(1)时间复杂度的操作。每张MyISAM表中存放了一个meta信息count值,在内存中与文件中各有一份,内存中的count变量值通过读取文件中的count值来进行初始化。SELECTCOUNT()FROMt会直接读取内存中的表t对应的count变量值。内存中的count值与文件中的count值由写操作来进行更新,其一致性由表级锁来保证。表级锁保证的写入串行化使得,同一时刻所有用户线程的读操作要么被锁,要么只会看到一种数据状态。四、几个问题
  Q:MyISAM与InnoDB在COUNT()操作的执行过程在哪里开始分道扬镳?共性:共性存在于SQL层,即SQL解析之后的数据结构是一致的,count变量都是存在于作为结果列的Itemsumcount类型对象中;返回给客户端的过程也类似对该count变量进行赋值并经由MySQL通信协议返回给客户端。区别:InnoDB的count值计算是在SQL执行阶段进行的;而MyISAM表本身在内存中有一份包含了表rowcount值的meta信息,在SQL优化阶段通过存储引擎的标记给优化器一个hint,表明该表所用的存储引擎保存了精确行数,可以直接获取到,无需再进入执行器。
  Q:InnoDB中为何无法向MyISAM一样维护住一个rowcount变量?
  A:从MVCC机制与行可见性问题中可得到原因,每个事务所看到的行可能是不一样的,其count()结果也可能是不同的;反过来看,则是MySQLServer端无法在同一时刻对所有用户线程提供一个统一的读视图,也就无法提供一个统一的count值。
  PS:对于多个访问MySQL的用户线程(COUNT())而言,决定它们各自的结果的因素有几个:一组事务执行前的数据状态(初始数据状态)。有时间重叠的事务们的执行序列(操作时序,事务理论表明并发事务操作的可串行化是正确性的必要条件)。事务们各自的隔离级别(每个操作的输入)。
  其中1、2对于Server而言都是全局或者说可控的,只有3是每个用户线程中事务所独有的属性,这是Server端不可控的因素,因此Server端也就对每个COUNT()结果不可控了。
  Q:InnoDBCOUNT()属tablescan操作,是否会将现有BufferPool中其它用户线程所需热点页从LRUlist中挤占掉,从而其它用户线程还需从磁盘load一次,突然加重IO消耗,可能对现有请求造成阻塞?
  A:MySQL有这样的优化策略,将扫表操作所load的page放在LRUlist的oungold的交界处(LRU尾部约38处)。这样用户线程所需的热点页仍然在LRUlistyoung区域,而扫表操作不断load的页则会不断冲刷old区域的页,这部分的页本身就是被认为非热点的页,因此也相对符合逻辑。
  PS:个人认为还有一种类似的优化思路,是限定扫描操作所使用的BufferPool的大小为O(1)级别,但这样做需要付出额外的内存管理成本。
  Q:InnoDBCOUNT()是否会像SELECTFROMt那样读取存储大字段的溢出页(如果存在)?
  A:否。因为InnoDBCOUNT()只需要数行数,而每一行的主键肯定不是NULL,因此只需要读主键索引页内的行数据,而无需读取额外的溢出页。
  blog。didiyun。comindex。php20190108mysqlcount
搜索 投诉 评论 转载

深入理解selectcount()深入理解selectcount()底层究竟做了什么2019061112:58Java技术架构专注于Java领域优质技术,欢迎关注作者:贾春生SELECT……40岁如何快速提升衣品?重新定位自己的穿衣,简单舒适减龄40岁的女生可以说是步入了大龄女的范围了,若是穿衣还是像二三十岁的时候,可能变得不再适宜,总有种装嫩的嫌疑。所以,40岁就是个门槛,是该重新定位自己的穿衣风格了。人到40……20个中成药,虽然价廉,但治疗疾病的疗效可不赖,很值得收藏暑湿感冒暑湿感冒颗粒。清暑去湿、芳香化浊。用于外感风寒引起的感冒,胸闷呕吐,腹泻便溏,发热不畅。痰热咳嗽金贝痰咳清颗粒。清肺止咳,化痰平喘。适用于痰热阻肺所致……伊藤美诚高兴早了!陈梦淘汰因祸得福,溃败出局却收更大惊喜北京时间11月29日,休斯顿世乒赛第六比赛日上演了一场强强对话,在大家高度关注的国乒一姐陈梦与日乒一姐伊藤美诚的较量中,陈梦最终败下阵来。本次两个人的交手虽然不是女单比赛,但也……她视角与奥迪一起探索旅行的意义如今,女性力量颠覆想象,她们宽容、执着、温柔、坚强、优雅,她们在自己的领域里发光发热,活出属于自己的风格。这个寒冬,封面新闻2021封格女性公益活动温暖来袭,点赞她力量,见证每……孩子老喊腿疼,到底是生长痛还是其它问题,这样判断在宝宝长大的过程中,难免会有些不舒服的地方,而有一种痛,会莫名其妙的开始,又莫名其妙的消失,让家长们倍感困扰,这就是所谓的生长痛。什么是生长痛其因为主要发作期在孩子312……党史上的今天12月13日重要论述1964年12月13日毛泽东审改周恩来准备向全国人大三届一次会议作的《政府工作报告》第四稿。在报告讲到在我们面前,仍然有一个很大的未被认识的领域,还有很多不……他18岁入党,55岁任辽宁省委书记,一生辛勤工作,活到78岁在我国,东北地区是一个非常重要的地区,从抗日战争初期被日军控制,到新中国成立后成为工业重心,国家能否快速发展和东北息息相关。在东北发展的这几年,出现了很多优秀的干部,今天为大家……Tiktok网红靠给婴儿起名字暴富!产后抑郁患者成韭菜从古至今,从来不缺赚钱好手,有些人总是能通过神奇的方式,获得可观的收入。来自纽约的33岁Humphrey,就搞起了给小婴儿起名字的生意。她所创办公司的名字,简单粗暴……小岳岳老婆有多辣,多汉子?结婚十年恩爱如初恋要说小岳岳老婆有多辣,多汉子?小岳岳对着老婆说土味情话被扔袜子,在机场嘟嘟嘴索吻时被老婆拒绝,夫妻在机场打闹看起来超有爱,难怪他们结婚十年恩爱如初恋。岳云鹏是如何认识他老婆的?……人老了,不在于运动,不在于喝水,请重视这3条准则常言道:三十而立,四十不惑,五十而知天命。年龄越大,尤其是到五十岁以后的年纪,健康就成为我们人生中的头等大事。一个人的身体健康是1,而财富、感情、事业、家庭都是1后……通州西集镇的村头公园吸引十余种野生动物安家随着北京平原造林工程持续推进,城市副中心生态环境大幅改善。森林多了,公园多了,如何吸引野生动物来安家?近年来,西集镇在实施村头公园工程中营建生物多样性保育小区,失踪多年的野鸡、……
资讯熊猫mini月销破1。2万辆?国轩高科称3月装车电池超12022年全球DDoS攻击现状与趋势分析报告发布孕期保持锻炼,饮食均衡也能缓解妊娠纹中国三迪2022年总收入约为人民币34。49亿元是蔡斌不放人还是李盈莹要价太高?土耳其球迷竟然造谣李盈莹看了就有食欲的甜品美食文案,还不收藏起来备用免费权益再缩水,腾讯会议要赚钱的心藏不住了中消协对46款充电数据线比较试验,仅14款安全华为孟晚舟身份突变,任正非曾说她永生永世不可能成为接班人累计通行100条!从禁酒到合理化,从酒文化看唐朝政权的兴衰看哭了,孩子给离世3年的父亲发信息被回复我的孩子是最棒的!
天猫搜索排名规则,双11坑位搜索排名规则曝光平安养老险创新推出契约保全直连服务,平均处理时效提升96【报名】乐施研讨:“疫情下不被看见的他们”国际残疾人日专题线认识你真好江城杂咏七首其六抗菌药物在不同组织的渗透性(表格版)秋天七年级作文750字移送审查起诉不受理的情形哪些?如何诊断及治疗脓毒性咽喉炎酸奶菌要怎么使用和保存酸奶菌使用方法有哪些信人造句用信人造句大全老人可以吃巧克力吗这些禁忌得牢记

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找菏泽德阳山西湖州宝鸡上海茂名内江三亚信阳长春北海西安安徽黄石烟台沧州湛江肇庆鹤壁六安韶关成都钦州