学习的文章:丁奇的mysql基础课1
说明:{mysql学习笔记N} 都是基于?各章节的文章,若有转载请务必注明出处
拿到一个问题,从高纬度出发,看清问题的前因后果,能够不断提高自己的认知水平。
下面记录下我的mysql学习笔记,按照作者思路走一遍。
start:首先拿到一个简单的查询语句
mysql> select * from T where ID=10;
一个查询,执行之后返回一条结果。发生了啥?为啥一串带特殊语法的句子能够从mysql返回对应的结果?我是要背诵这种语法来解决后续问题?这是原文作者给我的启发,技术要追根究底,这是一种态度。
引用mysql的架构图:
可以看到,从我这里主动查询的行为出发,经过了两个层次:server和db。可以形成一个直观的理解,就是server层给你做语义分析,去命中db的数据,然后返回结果。这是一个大体的认识。
那么细分下来,根据上图的直观显示,我们可以书写上面那个简单查询语句的流程了
1.mysql的连接
需要用户密码,服务地址的一个验证,打开通道。如果是直接使用mysql server服务器控制台操作,这个命令我们会非常熟悉:mysql -u -p,u->user,p->password,这个比较好理解,就是一个登录验证。。。要使用这个数据库,必须得要身份合法对吧
当然这里有个细节要注意:登录成功,连接器会到权限表里面(这个权限表我们可以自己查询,是mysql内置的表)查询当前用户的权限,之后连接器的所有权限判断逻辑都会以来这里读到的权限。即使这时候,更高级别的用户修改了这个角色的权限,这个权限变更会在下次建立连接的时候变更。
那么现在连接已经建立了------连接过程的建立到此结束,下面是拓展问题。
连接建立之后,连接器默认会保持这个连接8小时(同样也是mysql内置表保存这个配置,由参数wait_timeout配置),如果在失去这个连接的情况下继续给服务器发送数据库操作的请求,收到报错:lost connection to MYSQL server during query…这种情况就需要重新建立连接了。
这个连接类型,在数据库层面,称之为长连接,就是说如果持续有query请求,连接器会一直使用这个连接;对应短连接,就是说在每次执行很少几次query就断开连接,下次再有query就新建连接。
那么,这种长连接势必会带来问题,MYSQL使用的内存是管理在连接对象里面,如果连接数量越来越多必然会导致MYSQL占用内存持续增长,到临界值时发生OOM(out of memory),进而被系统强杀,这时候产生的现象就是,mysql异常重启了。解决问题的方案如下:定期断开(wait_timeout设置更短),或者程序在执行一个比较占用内存的大查询之后,直接断开这个连接,下次查询重新建立连接;升级到5.7以上的版本,可以在每次执行一个较大的查询之后,通过执行mysql_reset_connection初始化连接,这个连接是刚建立时候的状态,使用内存的记录已经被清空了,所以可以继续使用,但是连接并没有断开。
2.查询缓存
如果你配置了查询缓存,每次查询之后,缓存都会以key-value的形式存储在内存之中,如果再进来一个查询刚好是不久之前的key,那么我们称之为命中缓存,value会直接返回,你会发现这次的查询效率非常高(直接从内存中取数当然很高)。
查询缓存这个分支的流程大概就这样,下面是拓展知识。
先抛出一个建议:大多数情况下不要使用查询缓存。为啥?
如果单单查询,比如说元数据配置表,那么使用查询缓存是非常明智的。问题就出现在这里,一旦有更新表的操作,查询缓存都会失效,这样会导致你的查询缓存的命中率非常低。。(问题现象就是,一个很大的查询,耗时耗资源,你以为配置了查询缓存在短时间内可以一直查询不受约束,实际上一旦有更新操作,缓存都会失效,这是一个对你做好配置的误导)
但是mysql也提供了解决上述问题的方法,对指定查询使用缓存,这样短时间内每次查询直接取内存value。。值得一提的是,mysql8.0已经删除了这个解决办法。。
3.分析器
如果没有命中缓存(前提是你配置了查询缓存),那么现在要开始真正的入库查询了,首先,根据你的sql语法,mysql对这条语句做解析,这就是mysql的“语法分析”,如果不符合语法规则,返回错误:you have an error in your syntax。
此处无拓展…
4.优化器
经过上一步的分析,mysql知道了语法含义,在开始执行之前,还是要经过优化器的处理。下面介绍一下优化器。
当表里面存在多个索引的时候,优化器决定使用哪个索引,或者一条sql语句有多表关联的时候,决定各个表的连接顺序。具体的优化方法在这一章也没有说清楚,说后面会有具体分析,那么在后面的文章我也会记录。
经过优化之后,就到了具体执行的阶段。
此处拓展内容在后续的笔记…
5.执行器
开始执行的时候,会判断你的身份对当前表是否有查询的权限,没有的话就会直接返回权限错误,如果查询直接命中缓存,在返回缓存结果的时候做权限验证,在优化器之前也会做precheck权限验证。这里的权限验证你可能会产生疑惑:我在连接器那一步不是验证了我的身份了吗?为啥还要再做验证?
其实这里讨论的应该是两个问题,有数据库的登录权限,不带表拥有对表的操作权限。
如果拥有权限,就会打开表继续执行,这里举一个简单查询的例子:
mysql> select * from T where ID=10;
1.调用innoDB引擎取表的第一行,判断是否符合条件,是的话就吧这条记录存储到结果集,不是这跳过此行,
2.调用innoDB取下一行,依然史上一步的逻辑
3.遍历整个表,返回符合条件的记录
至此,这个查询语句就完成了。
有一个小点可以注意下,我们在观察mysql查询(慢查询,这个词后面解释)日志的时候,会看到rows_examined的字段,这个东西相当于这个查询线程对应到表内行数的“程序计数器”,是标识当前查询进度的字段,但是这个rows跟引擎扫描行数不是完全相同,查询引擎存在一次调用查询多行的情况(存储引擎的内部机制),这里的拓展知识后面会提及。
总结:
这篇笔记跟随作者思路大致的走了一遍mysql的逻辑架构,让我们对mysql的流程有了一个初步的了解,当然知识越学越细,要时刻保持追根究底的态度
来源:CSDN
作者:tianjingsha_persume
链接:https://blog.csdn.net/tianjingsha_persume/article/details/99617778