1. 客户端进程与服务器端进程间的通信方式

mysql运行中的服务器程序与客户端程序实际上是一个进程,所以客户端进程向服务器进程发送请求并得到相应的过程实际上是一个进程间的通信过程,而mysql支持以下几种客户端进程与服务器端进程间的通信方式

1.1 TCP/IP

在真实环境中,mysql的服务器进程与客户端进程可能运行在不同的主机中,他们之间必须通过网络进行通信,mysql采用TCP作为服务器与客户端之间的网络通信协议。

在网络环境下,每台计算机都有唯一的IP地址,如果某个进程需要采用TCP协议进行网络通信,就可以向操作系统申请一个端口号,端口号是一个整数值,他的取值范围是0~65535。这样网络中的其他进程就可以通过IP地址+端口号的方式与这个进程建立连接,这样进程之间就可以通过网络进行通信了。

mysql在服务器启动时会默认申请3306端口号,之后就在这个端口号上等待客户端进行连接。也就是说,mysql服务器会默认监听3306端口。如果3306端口被占用,或者我们想自定义端口号,就可以在启动服务器程序的命令行中来明确指定端口号。如下:
mysqld -P3307
这样mysql服务器就会在启动时去监听指定的端口号 3307
而当服务端端口号为3307时,在启动客户端时,可以这样写:
mysql -h127.0.0.1 -uroot -P3307 -P

1.2 命名管道与共享内存

如果你是一位windows用户,那么可以在服务器进程与客户端进程之间使用命名管道或共享内存进行通信,不过在使用这些通信方式的时候,需要在启动服务器程序和客户端程序时添加一些参数。

  • 使用命名管道进行进程间通信:启动服务器程序的命令上添加 --enable-named-pipe参数,然后在启动客户端程序的命令中加上
    –pipe 或者–protocal=pipe参数
  • 使用共享内存进行进程间通信:启动服务器程序的命令上添加 --shared-memory参数,然后在启动客户端程序的命令中添加 --protocol=memory参数

这里需要注意的是使用共享内存进行通信的服务器进程与客户端进程必须位于同一台windows主机中。

1.3 UNIX域套接字

如果mysql服务器进程与客户端进程都在类UNIX操作系统的同一台机器上,则可以使用UNIX域套接字进行进程间的通信。

如果在启动客户端程序时没有指定主机名,或者指定的主机名为localhost,又或者制订了 --protocol=socket的启动参数,那么服务器程序与客户端程序之间就可以通过UNIX域套接字进行通信了。

Mysql服务器程序默认监听的UNIX域套接字文件名称为 /tmp/mysql.sock,客户端程序也默认连接到这个UNIX域套接字文件名称。如果想修改名称可以在启动服务器程序的时候执行socket参数:
mysqld --socket=/tmp/a.txt
客户端需要像以下这样显式的指定连接的UNIX域套接字文件名称:
mysql hlocalhost -uroot --socket=/tmp/a.txt -p

2. 服务器与客户端的连接过程

客户端进程与服务器进程进行通信,最终实现的效果是客户端进程向服务器进程发送一段文本(Mysql语句),服务器进程处理后再向客户端进程返回一段文本(处理结果)。那么,服务器进程对客户端进程发送的请求做了什么处理呢。

客户端

处理连接 -连接管理

查询缓存 -解析与优化

语法解析 -解析与优化

查询优化 -解析与优化

存储引擎 -存储引擎

文件系统


上图为服务器程序在处理客户端的查询请求时,大致需要分为:连接管理、解析与优化、存储引擎。

2.1 连接管理

客户端进程可以采用前面的三种方式与服务器进程建立连接,每当有一个客户端进程连接到服务器进程时,服务器进程都会创建一个线程专门处理与这个客户端的交互,每当客户端断开连接时,服务器不会立即ixaohui该线程,而是将其缓存起来,以便于下次连接时使用,这样避免了频繁的创建及销毁线程,从而节省了开销。

在客户端程序发起连接请求时,需要携带主机信息、用户名、密码风信息,服务器程序会对客户端提供的信息进行验证。验证失败则拒绝连接。连接创建后,与该客户端关联的服务器线程会一直等待客户端发送请求。

2.2 解析与优化

服务器已经获得了文本形式的请求,接下来的几个比较重要的部分是查询缓存,语法解析,查询优化。

2.2.1 查询缓存

mysql处理查询请求时,会把刚刚处理过的查询请求以及结果还存起来,如果下一次有同样的请求过来,就直接从缓存中查找结果,就不需要再去底层查找了。这个查询缓存可以在不同的客户端之间共享。

如果两个查询请求有任何字符的不同(例如空格、大小写、注释),都会导致缓存不会命中。
如果查询请求中包含某些系统函数、用户自定义变量和函数、系统表等,则这个请求不会被缓存。
如果对缓冲中涉及到的表做了结构上的修改或者数据上的修改,那么与该表相关的所有的查询缓存都会变为无效,并从查询缓存中删除。

查询缓存的缺点:每次查询脚本过来后,都需要去缓存中检索,查询请求结束后需要更新查询缓存,这样会导致开销变大。从mysql5.7.20开始不推荐使用查询缓存,mysql8.0中直接删除查询缓存。

2.2.2 语法解析

上一步没有命中查询缓存后,正式进入查询阶段,客户端发过来的是一段文本,所以mysql服务器程序要对这段文本进行分析,判断语法以及要查询的表、各种条件都要提取出来放到mysql服务器内部使用的一些数据结构上。

从本质上述,该过程算是一个编译过程,涉及词法解析,语法分析,语义分析等阶段。

2.2.3 查询优化

在语法解析后,服务器获得了需要的信息(查询的表及字段等),但光是如此还是不够,因为我们写的sql执行效率不会很高,mysql的优化程序会对我们的语句做一些优化,优化的结果就是生成一个执行计划,可以使用explain取查看执行计划。

2.3 存储引擎

到查询优化为止,还没有真正的访问到真实的数据(在查询优化期间可能访问表中的少量数据),Mysql把数据的存储以及提取操作都封装到了存储引擎中,在物理上,表如何记录数据、怎么从表中读取数据、怎么把数据写入具体的物理存储器中,都是存储引擎负责的事情。

而在我们接下来的文章中,都是以InnoDB为默认引擎来操作。

今天的文章先到这里。