天天CURD,你了解为了执行SQL,MySQL用了怎样的架构设计吗?

大家好, 从今天开始我们开启MySQL底层原理的探索里程,今天是第一篇我们将MySQL从一个黑盒状态一点点拨云见日剖析来了解整个MySQL的架构设计和底层组件

image.png

把MySQL当作一个黑盒来执行SQL

现在我们来看看, 对于研发工程师来说数据库是什么东西?平时我们做系统开发时,一般情况下都会连接到一个MySQL数据库上去,去执行各种增删改查语句。如下图所示:


image.png

但是实际上我们在使用MySQL的过程中,总会遇到这样那样的一些问题,比如死锁异常、SQL性能太差、MySQL gone away等等。在遇到MySQL数据库的一些问题时,一般都会上网搜索博客,然后自己尝试捣鼓着解决一下,最后解决了问题,可能也没搞明白里面的原理。

因此我们就要去探索MySQL底层原理的方方面面,以及探索在解决MySQL各种生产实战问题的时候,以及如何基于MySQL底层
原理去进行分析、排查和定位。

如何连接到MySQL:MySQL驱动

大家都知道,如果我们要访问数据库,必须得跟数据库建立一个网络连接,那么这个连接由谁来建立呢?答案就是MySQL驱动,它会在底层跟数据库建立网络连接,有网络连接,接着才能去发送请求给数据库服务器!如下图所示:


image.png
数据库连接池

那么我们来思考一个问题,一个golang系统难道只会跟数据库建立一个连接吗?这样肯定是不行的, 对于一个稍微有点流量的站点来说,瞬时会有很多请求打过来,这个时候,都去竞争一个数据库连接的话,性能肯定很低下。
那么如果golang在访问数据库的时候,都创建一个连接,执行完后就释放,这样行不行?首先要明白的是数据库连接是有上限的,因为每次建立一个数据库连接都很耗时(tcp三次握手),好不容易建立好了连接,执行完了SQL语句,你还把数据库连接给销毁了,下一次再重新建立数据库连接,那肯定是效率很低下的 。


image.png

所以一般我们必须要用数据库连接池,也就是说在一个池子里维持多个数据库连接,让多个进程使用里面的不同的数据库连接去
执行SQL语句,然后执行完SQL语句之后,不要销毁这个数据库连接,而是把连接放回池子里,后续还可以继续使用。
基于这样的一个数据库连接池的机制,就可以解决连接争抢和效率问题,如图所示:


image.png
MySQL数据库的连接池

讲到现在我们已经知道,我们任何一个系统都会有一个数据库连接池去访问数据库,也就是说这个系统会有多个数据库连接,供程序并发
的使用。同时我们可能会有多个系统同时去访问一个数据库。
这个时候,我们将目光转移到MySQL本身,对于多系统要与数据库建立很多连接,那么MySQL必然也要维护与系统之间的多个连接才可以,所以,这里我们开始了解MySQL架构体系中的第一个环节,就是连接池。

如下图所示,实际上MySQL中的连接池就是维护了与系统之间的多个数据库连接。除此之外,你的系统每次跟MySQL建立连接的
时候,还会根据你传递过来的账号和密码,进行账号密码的验证,库表权限的验证。


image.png

讲到这里,我们还是把MySQL当作一个黑盒在使用,我们只知道执行了insert语句之后,在表里会多出来一条数据;执行了update语句之后,会对表里的数据进行更改;执行了delete语句之后,会把表里的一条数据删除掉;执行了select语句之后,会从表里查询一些数据出来。如果语句性能有点差?没关系,在表里建几个索引就可以了!

SQL线程:负责监听,读取请求

从现在开始就要打破这种把数据库当黑盒子的认知程度,要深入底层,去探索数据库的工作原理以及生产问题的优化手段!
现在我们的数据库服务器的连接池中的某个连接接收到了网络请求,假设就是一条SQL语句,那么我们先思考一个问题,
谁负责从这个连接中去监听网络请求?谁负责从网络连接里把请求数据读取出来?
其实这个时候,一定得有一个线程去处理网络连接,并由它来监听请求以及读取请求数据,比如从网络连接中读取和解析出来一
条我们的系统发送过去的SQL语句, 如下图所示:


image.png

SQL接口:负责接收SQL语句

那么接下来着我们思考一下,当MySQL内部的工作线程从一个网络连接中读取出来一个SQL语句之后,此时会如何来执行这个SQL语
句呢?
其实MySQL内部首先提供了一个组件,就是SQL接口(SQL Interface),它是一套执行SQL语句的接口,专门用于执行我们
发送给MySQL的那些增删改查的SQL语句,因此MySQL的工作线程接收到SQL语句之后,就会转交给SQL接口去执行,如下图。


image.png

查询解析器:让Mysql能看懂SQL

那么问题来了,SQL接口是如何执行SQL语句呢?你直接把SQL语句交给MySQL,他怎么能看懂和理解这些SQL语句呢?
比如我们来举一个例子,现在我们有这么一个SQL语句:

select id,name,age,sex from `user` where id=1;

我们用人脑是直接就可以处理一下,只要懂SQL语法的人,立马大家就知道他是什么意思,但是MySQL是一个数据库管理系统,他没法直接理解这些SQL语句!

  此时有一个关键的组件要出场了,那就是"查询解析器"
这个查询解析器(Parser)就是负责对SQL语句进行解析的,比如对上面那个SQL语句进行一下拆解,拆解
成以下几个部分:
 1) 我们现在要从“users”表里查询数据
 2) 查询“id”字段的值等于1的那行数据
 3) 对查出来的那行数据要提取里面的“id,name,age”三个字段。
所谓的SQL解析,就是按照既定的SQL语法,对我们按照SQL语法规则编写的SQL语句进行解析,
然后理解这个SQL语句要干什么事情

如下图所示:


image.png

查询优化器:选择最优的查询路径

当我们通过SQL解析器理解了SQL语句要干什么之后,接着会找查询优化器(Optimizer)来选择一个最优的查询路径。这里我们可以用一个极为通俗简单的例子,来理解一下所谓的最优查询路径是什么。
我们现在理解了一个SQL想要干这么一个事儿:我们现在要从"users"表里查询数据,查询id字段的值等于1的那行数据,对查出来的那行数据要提取里面的"id,name,age"三个字段。
事情明白了,但是到底应该怎么来实现呢?这里我们来简单分析下有以下两种查询路径:

1) 直接定位到"users"表中的id字段等于1的一行数据,然后查出来那行数据的"id,name,age"三个字段
的值就可以了
2) 先把"users"表中的每一行数据的"id,name,age"三个字段的值都查出来,然后从这批数据里过滤出来
id字段等于1的那行数据的"id,name,age"三个字段

其实我们会发现,要完成这个SQL语句的目标,两个路径都可以做到,但
是哪一种更好呢?显然感觉上是第一种查询路径更好一些。
所以查询优化器就是干这个的,它会针对你写的几十行、几百行甚至上千行的复杂SQL语句生成查询路径树,然后从里面选择一条最优的查询路径出来。相当于他会告诉你,你应该按照一个什么样的步骤和顺序,去执行哪些操作,然后一步一步的把SQL语句就给完成了。如下图所示:


image.png

存储引擎接口,真正执行SQL语句

这个时候把查询优化器选择的最优查询路径计划交给底层的存储引擎去真正的执行。这个存储引擎是MySQL的架构设计中很有”特色”的一个环节。
不知道你有没有思考过,真正在执行SQL语句的时候,要么更新数据,要么查询数据,那么数据你觉得存放在哪里?
其实数据库就是一个C、C++语言写出来的系统而已,然后启动之后也是一个进程,执行他里面的各种代码,也就是我们上面所说的那些东西。所以对数据库而言,我们的数据要不然是放在内存里,要不然是放在磁盘文件里,没什么特殊的地方!

   所以我们来思考一下,假设我们的数据有的存放在内存里,有的存放在磁盘文件里。那么问题来了,
我们已经知道一个SQL语句要如何执行了,但是我们现在怎么知道哪些数据在内存里?哪些数据在磁盘里?
我们执行的时候是更新内存的数据?还是更新磁盘的数据?我们如果更新磁盘的数据,是先查询哪个磁盘
文件,再更新哪个磁盘文件?到这里是不是感觉一头雾水?
所以这个时候就需要"存储引擎"了,存储引擎其实就是执行SQL语句的,他会按照一定的步骤去查询内存
缓存数据,更新磁盘数据,查询磁盘数据,等等,执行诸如此类的一系列的操作
image.png

在MySQL的架构设计中,SQL接口、SQL解析器、查询优化器其实都是通用的,就是一套组件而已。
但是存储引擎的话,他是支持各种各样的存储引擎的(MySQL支持插件式引擎),比如我们常见的InnoDB、MyISAM、Memory等等,我们是可以选择使用哪种存储引擎来负责具体的SQL语句执行的。
当然现在MySQL5.7都是使用InnoDB存储引擎的,至于存储引擎的原理,后续我们也会深入一步一步分析的

执行器:根据执行计划调用存储引擎的接口

这个时候我们再来思考一个问题,既然存储引擎可以帮助我们去访问内存以及磁盘上的数据,那么是谁来调用存储引擎的接口呢?
我们是不是还漏了一个执行器的概念呢?这个执行器会根据优化器选择的执行方案,去调用存储引擎的接口按照一定的顺序和步骤,就把SQL语句的逻辑给执行了。
这里举个例子,比如执行器可能会先调用存储引擎的一个接口,去获取"users"表中的第一行数据,然后判断一下这个数据的
id字段的值是否等于我们期望的一个值,如果不是的话,那就继续调用存储引擎的接口,去获取"users"表的下一行数据。就是基于上述的思路,执行器就会去根据我们的优化器生成的一套执行计划,然后不停的调用存储引擎的各种接口去完成SQL语句的执行计划,这样整个流程就串起来了,如下图所示:


image.png

到这里,我们将MySQL内部是如何去执行一条SQL的整个流程详细的剖析了一遍,可以简单了解了内部各个组件的作用。下面奉上一张极客时间中MySQL45讲专栏关于MySQL执行的逻辑架构图:


Mysql的逻辑架构图

下一篇我们将会讲"从一条SQL更新语句来了解InnoDB存储引擎的架构设计", 敬请期待。。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容