引入
我们的系统采用数据库连接池的方式去并发访问数据库,然后数据库自己也会维护一个连接池,其中管理了各种系统跟这台数据库服务器建立的所有连接。
我们的系统只要能从数据库连接池中获取一个数据库连接之后,就可以执行增删查改的SQL语句了。
从上图可以看到,我们可以通过数据库连接将要执行的SQL语句发送给MySQL数据库。
那MySQL数据库到底是怎样执行SQL语句的呢?
MySQL是怎样执行SQL语句的
一个不变的原则:网络连接必须让线程处理
假设我们的数据库服务器的连接池中的某个连接收到了网络请求,假设就是一条SQL语句,那么:谁负责从这个连接中监听网络请求?谁负责从网络连接里吧请求数据读出来?
必须要知道的是,网络连接必须分配一个线程去进行处理,由一个线程来监听请求以及读取请求数据,比如从网络连接从读取和解析出来一条外部系统发送过去的SQL语句。
SQL接口:负责处理接收到的SQL语句
问题:当MySQL内部的工作线程从一个网络连接中读取出来一个SQL语句之后,此时会如何来执行这个SQL语句呢?
首先MySQL内部会提供一个组件,就是SQL接口(SQL Interface),它是一套执行SQL语句的接口,专门用于执行我们发送给MySQL的那些增删查改的SQL语句。
也就是说,MySQL工作线程接收到SQL语句之后,就会转交给SQL接口去执行:
查询解析器:让MySQL能够看懂SQL语句
问题: SQL接口怎么执行SQL语句呢?你直接把SQL语句交给MySQL,他能看懂和理解这些SQL语句吗?
举个例子,假设当前有这么一个SQL语句: select if, name, age from users where id = 1
这个SQL语句,我们用人脑是直接就可以处理一下,只要懂SQL语法的人,立马大家就知道他是什么意思,但是MySQL自己本身也是一个系统,没法直接理解这些SQL语句。
所以此时就有一个关键的组件出现了,那就是查询解析器。它是负责对SQL语句进行解析的。比如对上面那个SQL语句进行一下拆解,拆解成以下几个部分:
- 我们现在要从“users”表里查询数据
- 查询“id”字段的值等于1的那行数据
- 对查出来的那行数据要提取里面的“id,name,age”三个字段。
所谓的SQL解析,就是按照既定的SQL语法,对我们按照SQL语法规则编写的SQL语句进行解析,然后理解这个SQL语句要干什么事情。
查询优化器:选择最优的查询语句
通过解析器理解了SQL语句要干什么之后,接着就会找查询优化器来选择一个最优的查询路径。
相当于它会告诉你,你应该按照一个什么样的步骤和顺序,去执行这些操作,然后一步一步的把SQL语句完成了
调用存储引擎接口,真正执行SQL语句
最后一步,就是把查询优化器选择的最优查询路径,也就是你到底应该按照一个什么样的顺序和步骤去执行这个SQL语句的计划,把这个计划交给底层的存储引擎去真正的执行。这个存储引擎是MySQL的架构设计中很有特色的一个环节。
真正在执行SQL语句的时候,要不然是更新数据,要不然是查询数据,那么数据应该存放在哪里呢?
数据库自己就是一个编程语句写出来的系统而已,然后启动之后也是一个进程,执行它里面的各种代码,也就是我们上面说的那些东西。所以对数据库而言,我们的数据要不就是放在内存中,要么就是放在磁盘中。
那么问题来了,我们已经知道一个SQL语句要如何执行了,但是我们现在怎么知道哪些数据在内存里,哪些数据在磁盘里?我们执行的时候是更新内存的数据,还是更新磁盘的数据呢?如果我们更新磁盘的数据,是怎么查询/更新磁盘文件的呢?
所以这个时候就需要存储引擎了。存储引擎其实就是执行SQL语句的,它会按照一定的步骤去查询内存缓存的数据,更新磁盘数据,查询磁盘数据等执行诸如此类的一系列的操作
MySQL的架构设计中,SQL接口,SQL解析器,查询优化器其实都是通用的,他就是一套组件而已。
但是存储引擎的话,它支持各种各样的存储引擎的,比如InnoDB、MyISAL等。我们是可以选择使用哪种存储引擎来负责具体的SQL语句执行的。
当然现在MySQL一般都是使用InnoDB存储引擎的
执行器:根据执行计划调用存储引擎的接口
问题:存储引擎可以帮助我们去访问内存以及磁盘上的数据,那么是谁来调用存储引擎的接口呢?
这就需要执行器了。这个执行器会根据优化器选择的执行方案,去调用存储引擎的接口按照一定的顺序和步骤,把SQL语句的逻辑执行了。
也就是说,执行器会根据优化器生成的一套执行计划,然后不停的调用存储引擎的各种接口去完成SQL语句的执行计划,大致就是不停的更新或者提取一些数据出来。