2 mysql底层解析——表对象缓存,包括连接、解析、缓存、引擎、存储等

Wesley13
• 阅读 621

学习了mysql的连接层之后,要来看一下mysql的server层了。这一层聚集了mysql的最多的逻辑,包括了请求解析、查询缓存、语义分析、查询优化、各种计算函数、扫描记录、binlog、缓存、锁、内存管理等等。

当一个连接建立起了,用户发过来一个sql语句,从接到这个语句到返回给用户结果,这个过程中,经历了很多事,如果每一步都非常清楚,那么你就能解决大部分的问题。

这一篇主要是讲表对象缓存。

我借用一下别人画的一个图

2 mysql底层解析——表对象缓存,包括连接、解析、缓存、引擎、存储等

创建表

假如你已经创建好了一个表,设置好了列、列属性,索引什么的,并且指定好了存储引擎(默认innodb)。

表对象缓存

用户发过来一个sql,譬如select * from tableA where id =1;此时mysql拿到了这个请求,会先到查询缓存中看,之前是不是执行过这个语句。缓存里key就是这个查询语句,如果查询缓存有,那么就直接返回value给客户端。这个查询缓存是个非常鸡肋的东西,新版8.0已经把它删掉了。这里也不多提。

mysql收到请求后,会进行sql语句解析,会分析出,你是查询(插入、删除),哪个表(tableA、tableB),条件。然后先判断sql语句是否合法,假如你写了个selector * 那么就会报错给你看。

ok,要进入正题表对象缓存了。

解析出了表之后,要得到这个表的各种信息。

一级表结构缓存

我要操作表了,首先我要找到这个表。先从缓存中(源码里的table_def_cache,是一个Hash结构)找,根据表名做为Key去找,由于我是第一次访问这个表,缓存里没有。那么就会从System表里去找,熟悉mysql元数据的应该知道,元数据里有每个表的定义,列信息什么的都在表里。找到了这个表,就会构建出这个表的结构体TABLE_SHARE。

这个TABLE_SHARE是一个静态的、不允许修改的(在内存中)结构体TABLE_SHARE,并将其放入缓存中(一个Hash结构里,key就是表名+模式名)。可以理解为一个java里的类,每个字段已经被赋了初始值。这个缓存是属于mysql层的,与后面的存储引擎无关。里面保存了表名、库名、所有列信息、列默认值、表的字符集、对应的frm文件路径、对应的存储引擎、主键等。

请注意,这个结构体就是一级缓存,它被所有用户共享,并且不可修改,从系统表被读入直到该表被修改或删除,这个缓存都会一直存在。

二级表对象缓存

表已经找到了,结构也已经被缓存了,此时我还不能操作这个表。因为缺少一个表对象。

上面的TABLE_SHARE可以理解为一个模板类,包含了表的基本信息,能被所有用户共享。但是里面还缺少一些信息,譬如不同用户对该表的权限、譬如存储引擎信息。那么要想操作这个表,就需要创建一个表对象来供当前用户(线程)使用。

创建表对象就是实例化的过程,每个用户独享一个实例,我们称之为table实例,不会影响其他用户。创建的这个实例,里面有一个指向TABLE_SHARE的引用,用以获取基本信息,还有一些其他属性,譬如存储引擎层的信息也会被初始化(引擎的handler)。

表对象创建完毕后,就具备了和存储引擎交互的能力(通过handler)。创建后,也会放入缓存,供下次使用时避免反复创建实例。

mysql层与存储引擎层,就是从这里开始分家的,table对象就是他俩沟通的桥梁。对于各个存储引擎,需要提供公共的接口来供上层(mysql server)层来调用,并由各自的table实例来完成各自的操作。
譬如插入一条记录,就可以调用table实例中被初始化过的存储引擎的句柄接口函数ha_write_row,进行写入。

这个table实例在一次操作完成之后就不需要了,系统此时并没有将其释放掉,而是保存下来,用一个状态标志位标记一下,并且会调用handler.reset()来重置引擎表状态,目的是handler会被复用,如果不reset,可能导致信息错误。缓存后,当下次用户再访问时,就不需要重新实例化了。

总结

可以看到,当你想操作一个表时,系统对于这个表,会有两层缓存。第一层是SHARE缓存,第二层就是实例化后的对象缓存Table。

是缓存就有淘汰策略,其实我们自己就能判断出来,SHARE缓存只有在表结构定义改变时,才会被删除,但是倘若表巨多,SHARE缓存超出限制,也会淘汰那些不经常使用的SHARE。

第二层的实例缓存,也是有最大值的,超出后则开始淘汰。

涉及的参数变量有两个,table_open_cache和table_definition_cache,一些淘汰策略数值就是靠这两个参数来计算得到的。当你有巨多的表时,可以网上查查这两个参数的涵义,适当调整修改。

优缺点

不同于某些数据库,一启动就加载了所有表信息。mysql是按需加载,由于mysql的插件式存储引擎,mysql做了两层的缓存模型,第二层才加载引擎的handler。

优缺点:
按需加载,提高内存利用率,避免启动时加载所有表信息带来的内存占用。

缺点:
两层缓存带来了效率的损失,每个用户(线程)都要实例化table对象。
在并发情况下,有可能会实例化多个table对象,导致table_open_cache增长过快,导致淘汰掉其他的table对象。同时倘若table比较大,譬如有N多的列,那么会占用非常多的内存。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这