设为首页 收藏本站
查看: 530|回复: 0

[经验分享] MySQL源码:MYSQL存储过程/函数的分析原理及缓存机制

[复制链接]

尚未签到

发表于 2018-10-4 12:10:56 | 显示全部楼层 |阅读模式
  前言:我个人认为,有关MYSQL存储过程/函数在MYSQL中的实现比较粗糙,可扩展性不够好,其实现的耦合性太高,所以主要讲一些它的原理方面的内容,但有可能在某些方面理解不够好或者有些不正确的地方,欢迎指正,谢谢!
  2012-5-14 by whuai QQ:329570985 欢迎指正!
  在MYSQL中,同样有很多类型的系统对象,包括表、视图、存储过程、存储函数等,但由于MYSQL的插件式存储引擎及其它实现方面的特点,其每一种对象的缓存方式都不同,或者说这些对象的缓存不是通过一种统一的方式来管理的,每一种对象的缓存都是有自己的特点,并且缓存的内容也有很大的差异,下面再叙述一下存储过程(PLSQL)缓存方式。
  MYSQL数据库管理系统中的存储过程/函数也是有缓存机制的,存储过程/函数实际上是用户通过创建存储过程的语句创建好的系统对象,它具有指定的名字、类型(存储过程/函数)及要执行的语句序列等。例如下面就是一个创建过程的语句:
  create procedure p()
  begin declare a int default 100;
  declare b int default 1000;
  declare d int default 1000;
  begin
  declare c varchar(100) default 'hello world';
  insert into my values(a, c);
  end;
  end;
  上面创建的过程名字为p,下面定义了一些变量并且都赋了初始值,一对BEGIN及END标志了一个语句块的内容,语句块可以嵌套定义,比如上面就在第一对BEGIN及END之间又定义了一对BEGIN及END,每一个语句块中又可以单独定义自己的变量,同时这些变量又有自己的可见性范围,假设在内层语句块中定义了一个变量,在外层同时又定义了一个同名的变量,那么在内层引用这个变量时实际上是内层定义的变量,而这个变量在外层是不可见的,可以引用到的只能是外层定义的变量。
  在实现上(基于源代码的分析),一个存储过程/函数分析后会得到一个sp_head结构体对象,这个对象唯一对应一个存储过程,而每一个语句块对应一个sp_pcontext结构对象,这个对象之间存在着父子关系,一个父亲可以有多个孩子,一个孩子只能有一个父亲,比如上面例子中的存储过程语句,整体的存储过程P就对应一个sp_head结构体对象,第一个BEGIN对应的语句块是父sp_pcontext,而其中又包括了一个语句块,这个语句块是父语句块的一个子语句块,在分析之后同样会生成一个sp_pcontext对象,它是一个子语句块对象,sp_pcontext结构体内有一个成员m_parent,它会指向父语句块,实际上这个语句块可以被称为一个“上下文环境”,因为它是可以被看作像C语言中的一个语句块,比如用{}括起来的一段代码一样。
  在进行语法分析sp_compile时,MYSQL会对每一条分析的语句都生成相应的指令,这些指令都被顺序存储到类型为DYNAMIC_ARRAY的动态数组m_instr中,这是用来存储所有的这个存储过程的指令的,比如对于上面语句“declare b int default 1000;”,系统首先会分配一个变量的存储空间,变量被放在sp_pcontext对象中,也是通过一个动态数组m_vars来存储的,因为变量是语句块级的,而上面这条语句还对应的一个操作就是给这个变量赋初始值,所以系统要创建一个指令给这个变量设置初值,这个指令为sp_instr_set,每一个指令都需要实现一个执行函数exec_core,这个函数是一个虚函数,每一种指令的执行都要实现自己的执行函数,就比如上面这个设置变量的指令,它的实现是调用了函数set_variable来给指定的变量设置指定的初始值即可。
  对于不同的操作,有不同的指令,MYSQL包括的指令有:sp_instr_stmt(执行SQL语句的指令)、sp_instr_set(设置变量的指令)、sp_instr_set_trigger_field(设置触发器中涉及到NEW/OLD变量的值的指令)、sp_instr_jump、sp_instr_jump_if_not(执行跳转指令)、sp_instr_freturn(函数返回指令)、sp_instr_cpush(游标声明指令)、sp_instr_copen(打开游标的指令)、sp_instr_cclose(关闭游标的指令)、sp_instr_cfetch(从游标取数据的指令)等,在PLSQL中涉及到这些操作后,都会创建相应的指令,并加入到sp_head的指令动态数组中,执行时会通过顺序或者跳转的方式执行。
  在PLSQL中,本人最感兴趣的是变量的引用,包括本地变量及上层语句块的变量的引用,系统是如何正确的找到相应的变量的?或者是通过什么方式来找到的?其实sp_head中的每一个变量都对应一个编号,是按照分析顺序生成的。变量是在sp_pcontext中定义的,也就是说变量的存储单元是语句块(sp_pcontext),一个语句块中可以有多个变量。同时在每一个语句块结构体sp_pcontext中都有一个表示这个语句块中所定义的变量的编号的范围,一个起始ID及变量个数,因为sp_pcontext是按照父子关系来联系的,那么一个语句块的开始变量ID号是其前面平行的语句块的开始ID号加1的值,如果它本身就是第一个语句块,则其起始语句块的变量ID号为其父语句块的结束ID号加1的值。所以这样就给每一个语句块指定了唯一的互不包含的变量ID号的范围。
  那么要引用一个变量时,找到其在符号表中的对象是很容易的,因为对每一个指令而言,都有一个指针指向其所属的sp_pcontext,同时每一个引用变量操作对应的指令都记录了这个变量的ID号,这样系统可以直接根据sp_pcontext中的超始ID号及变量的个数计算出当前这个被引用的变量对应的ID号是否在当前语句块sp_pcontext中,如果是则直接从sp_pcontext的变量动态数组m_vars中找到对应ID的变量对象,如果没有找到,则说明这个变量有可能是在父语句块中定义的,则通过sp_pcontext中的m_parent找到其父语句块,用同样的方法找对应的变量,如果找到则已,找不到继续向上,依此类推,直到找到在某一个语句块中的这个变量,或者m_parent为空的时候则说明没有找到,则说明这个引用是一个对未定义的变量的引用,直接报错即可。那么通过上面的方法只要找到这个变量对象,则对其访问或者给它赋值,都可以直接访问其成员函数即可。
  由于PLSQL的数据类型及支持语句比较多,这里只介绍一些比较重要的原理,从上面所叙述的内容可以对PLSQL的分析、指令的生成及运行原理有一个大概的轮廓,从总的结构来讲,存储过程/函数生成的计划就是一个sp_head对象,sp_head中包含了所有生成的指令,在运行过程中按照指令顺序或者内部逻辑的跳转来执行。另外生成一个语句块的树形结构,每一个树节点为sp_pcontext结构对象,其中m_parent指向其父节点,同时每一个sp_pcontext还存储了所有的子语句块链表,PLSQL中定义的变量都存储在sp_pcontext中。
  本文还要讲另外一个内容就是存储过程/函数对象的缓存机制,其实在MYSQL中,缓存的并不是存储过程/函数的字典定义的对象,也就是说不是像之前讲的表对象的字典缓存,而是将整个分析好的sp_head对象缓存起来了。那么说白了,MYSQL的存储过程/函数字典的缓存其实是其执行计划的缓存。只要执行过一次,那么只要没有将这个存储过程/函数删除,再次执行时只需要从缓存空间中找到这个计划拿出来直接执行即可,这样就提高了存储过程/函数的执行效率,不需要再进行词法、语法、语义、指令的生成等这些步骤了。
  总结:在MYSQL中的存储过程/函数的分析过程将上面提到的所有步骤都揉合到了一起,也就是说:词法分析、语法分析、语义分析、指令的生成这些步骤的分析过程没有一个阶段性的区分,没有明显的区分各个阶段的工作,而是将所有这些步骤都一起完成,每分析一条语句,词法、语法做完之后,直接分析这条语句中的语义、判断定义的变量是否存在、确定变量在语句块中的位置,合法之后直接创建变量的空间,同时还要分配一个指令,为这个变量设置初始值等操作,所有这些直接在语法文件中完成了,在实现上难免非常混乱。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-611836-1-1.html 上篇帖子: 【MYSQL】Mysql 设备选型与系统规划-实战参考文档-带附件-可下载 下篇帖子: MySQL(一)之通用二进制格式安装MySQL及数据库基本概念
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表