标贝科技 https://ai.data-baker.com/#/?source=qwer12

填写邀请码fwwqgs,每日免费调用量还可以翻倍

Mysql整体介绍(适用于5.X版本)(标贝科技)

Mysql 8.X版本和 5.X版本相比,有比较大的调整。目前工作中应用最广的是Mysql 5.6/5.7的版本,所以文章将聚焦于对Mysql 5.6/5.7版本进行介绍,8.X版本的相关改动,有机会再单独整理。

一、Mysql体系结构

Mysql是一个单进程多线程、基于C/S架构的关系型数据库管理系统,其体系结构如图1所示(图片参考Mysql官方手册,各个版本会进行少许调整,总体上仍是准确的,虚线标出的查询缓存和缓冲区部分在Mysql 8.X版本中已废弃,侧面反映了数据库的查询缓存实际上比较鸡肋)。客户端是一个广义的概念,指提供连接能力的各种组件和API。服务端包括连接池、管理组件和工具类、SQL接口、解析器、优化器、缓存、插拔式存储引擎、文件系统等许多组件。

图1 Mysql体系结构

1.1 C/S通信协议相关内容

在服务器启动的过程中,会完成创建套接字并绑定端口等工作。然后会在handle_connections_methods()函数中完成监听,监听其实就是等待用户的连接请求。这个函数中会处理三种连接方式:命名管道、套接字及共享内存。由于大多情况下,会采用套接字的连接方式,其他连接方式只有在一定条件下才能使用,所以本文只介绍套接字相关的部分。
MySQL客户端进程和服务器进程的Connection Pool之间是基于Mysql Client/Server协议[1]进行通讯的,该协议用于连接、代理、主备复制等操作,支持 SSL、压缩等特性。
Mysql C/S协议的内涵比较丰富,它规定了连接的各个生命周期的数据格式和行为,包括:各数据类型的编码格式、各种操作的请求数据包的格式、结果返回包的格式、字符集、数据包压缩和数据包TLS加密等等。
连接的生命周期包括三部分内容:连接阶段 (Connection Phase)、请求阶段 (Command Phase) 和拷贝协议 (Replication Protocol)。其中,拷贝协议比较独立,主要用于主从节点间的binlog同步。其大体流程是:建立连接后,Client向Server发送一个MySQL binlog dump的命令,随后,Server不断地给Client发送binlog event。本文不再详细介绍,如果希望进一步了解,推荐查看go-mysql-elasticsearch作者写的这篇文章:深入解析MySQL replication协议[3]。下面我们重点介绍一下连接阶段和请求阶段。

1.1.1 连接阶段(Connection Phase)通信

1.协议数据包
先简单介绍Mysql协议的数据包(packet)[2],Mysql的数据包均由header和body两部分构成:header总共有4个字节,3个字节用来标识 payload 的大小,1个字节记录sequence ID,来保证交互时报文的顺序;body则保存实际的负载数据(payload)。

这是Mysql最基础的数据包结构,所有具体操作的数据包都是基于这个数据包结构进行扩展的,即不同的操作对应不同的负载数据,具体的载荷内部结构可以自行查阅官网。此外,如果数据包的大小大于16MB,会被拆包。
2.工作流程
Mysql的连接阶段主要包含“握手”和“认证”两个步骤,具体参考图2。

图2 Mysql连接阶段时序图
3.握手
Mysql版本众多,客户端和服务端版本不一定匹配,二者支持的功能需要有个协商的过程,这就是“握手”部分的主要工作。协商时最主要依赖的是capabilities flags,这是一种功能标志,具体内容如图3所示,包括是否支持压缩功能、是否支持CLIENT_PROTOCOL_41版本协议、是否使用SSL加密等等。
4.认证
“握手”完成后,执行“认证”操作。MySQL的认证授权采用插件方式实现,默认采用mysql_native_password 插件[5]。该插件的核心逻辑在函数scramble()中,该函数通过用户输入的password、服务器返回的scramble生成reply,返回给服务端;服务端再与数据库信息或缓存信息进行比对。
MySQL 的用户管理模块信息存储在系统表mysql.user中,其中包括了授权用户的基本信息以及一些权限信息。在登陆时,只会用到 host、user、passwd 三个字段。服务器在收到新的连接请求时,会调用 login_connection() 方法进行身份验证,先根据 IP 做 ACL 检查,然后才进入用户名密码验证阶段。

图3 Mysql capabilities flags介绍[4]
下面简单对user、db、table_priv和columns_priv这几张系统表的含义进行说明。其中,user表是全局级的权限和信息,修改后可能发生对已有连接不生效的情况。

  • user:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。
  • db:记录各个帐号在各个数据库上的操作权限。
  • table_priv:记录数据表级的操作权限。
  • columns_priv:记录数据列级的操作权限。

Mysql这么处理,是为了保证效率,它在每个连接的内存里缓存了user表中的用户信息和权限信息。直接修改磁盘中user表的用户密码、权限等信息,是不会马上同步至内存的。要解决这个问题,只需执行“flush privileges;”即可,该操作的实质是:将系统表mysql.user中的用户信息和权限设置从磁盘中重新获取,并缓存到内存数组里。
5.线程缓存和线程池
在5.6版本以前,Mysql处理连接的方式是One-Connection-Per-Thread,即对于每一个数据库连接,Server端都会创建一个独立的线程服务。不过,Mysql也提供了thread-cache机制来缓解频繁创建和释放线程的问题(由图1中“Connection pool”内的“Thread Reuse”子模块实现),我们可以将线程缓存起来,以供下次使用,但是它仍然无法解决高连接数的问题。
从5.6版本开始,Mysql在服务端提供的一个重要功能:线程池。线程池是一种有效的技术,通过预先创建一定数量的线程,当有请求达到时,线程池分配一个线程提供服务,请求结束后,该线程又去服务其他请求或者进入睡眠状态。
线程池和线程缓存方案的区别在于:线程池方案每个线程服务的最小单位是SQL语句,即一个线程可以对应多个活跃的连接。它避免了线程大量创建销毁带来的性能消耗,同时解决了高连接数引起的高内存消耗问题。

1.1.2 请求阶段(Command Phase)通信

如果只关注客户端和服务端的通信过程,其实非常简单:客户端通过建立好的连接向服务端发送数据包,服务端接收到数据包后,解析并按照客户端要求去执行命令,然后将结果集返回至客户端。
但Mysql的C/S协议关于请求阶段的内容其实非常丰富,因为它既包含了客户端和服务端之间的通信部分,也包含了服务端内部交互的命令的相关规定。总体而言,C/S协议为请求阶段规定了4个方面内容:文本协议 (Text Protocol)、通用命令 (Utility Commands)、预编译语句 (Prepared Statements)、存储程序 (Stored Programs)[6]。
1.文本协议(Text Protocol)
只包含COM_QUERY命令,该命令规定了客户端的请求数据格式和服务端返回的数据格式。
客户端请求的格式比较简单,其payload的基本结构如表1所示 (某些条件下可能包含其他内容),其中“string[EOF]”表示字符串在payload的最后,它的特点是字符串的长度可以通过包的大小和当前初始位置计算出来[7]:


图4 COM_QUERY响应结果示意图[1]
服务端返回的数据格式相对复杂,参考图4。可以看出返回包含4种情况:
1). 如果执行错误,比如SQL语法错误,返回ERR包,即0xFF标志;
2). 如果执行成功,但没有查到任何数据,返回OK包,即0x00标志;
3). 如果客户端的执行导入数据操作 (load data local infile ‘filename’ into table ),
则返回方式遵循"本地文件导入"子协议 (Protocol::LOCAL_INFILE_Request)。协议的定义如图5所示:服务端收到请求后,将0xfb标志和文件名返回给客户端,表示希望获取文件数据(GET_MORE_DATA),客户端收到后发送文件数据 (SEND_MORE_DATA),结束后服务端返回OK包或者ERR包;

图5 LOCAL_INFILE_REQUEST子协议的交互过程[7]
4). 其他情况服务端将遵循“结果集"子协议(ProtocolText::Resultset):结果集的第一包含有列长度信息(FIELD_COUNT,LengthEncodedInteger类型,存储列的个数);接下来是n个字段描述包,每一个字段描述就是一个包(Protocol::ColumnDefinition);当所有字段信息描述包发送完成后,会发送一个EOF包或OK包(5.7版本之前如果没有设置CLIENT_DEPRECATE_EOF标记,会发送EOF包,5.7后均返回OK包)作为字段定义与数据(Row)的分隔符号;接下来是行数据包(Protocol::ColumnDefinition),每一行一个数据包;最后的结束包,同样可能是EOF或OK包,如图4"Text Resultset"部分所示。
注:EOF数据包的格式比较简单,它主要用于标明查询结果的结尾,包内带有两个信息:警告数和状态码。在5.7.5版本之后,已被改进版的OK数据包替代
2.通用命令(Utility Commands)
通用命令包括:COM_QUIT、COM_INIT_DB、COM_FIELD_LIST、COM_REFRESH、COM_STATISTICS、COM_PROCESS_INFO、COM_PROCESS_KILL、COM_DEBUG、COM_PING、COM_CHANGE_USER、COM_RESET_CONNECTION、COM_SET_OPTION等。其中,COM_REFRESH、COM_PROCESS_INFO、COM_PROCESS_KILL等已被标志为deprecated,可能在较新的版本中会被替换成其他的命令来实现。
下面对常用的几个命令进行简单的说明:COM_QUIT用于断开和服务端的连接;COM_PING用来测试服务端是否处于alive状态;COM_CHANGE_USER用于切换当前连接的用户信息,会执行与握手阶段类似的认证操作流程并重置连接的状态。
3.预编译语句(Prepared Statements)
预编译是Mysql在4.1版本之后引入的,它包括两大步骤:

  1. . 客户端提交不传递真实的参数值的SQL,服务端完成预编译解析,这里的预编译解析包括解析参数的个数、类型等,然后响应给客户端;
//不传递真实参数值的SQL的示例
insert into sys_user(id, name) values(?, ?);
select * from `sys_user` where id = ?;

2). 客户端第二次传数据时,只传递参数,服务端收到后就可以完成一个完整的SQL的执行,并返回结果。
相比4.1版本之前的SQL执行方式,预编译方式需要两次交互,才能完成一次SQL执行,表面看增加了步骤,实际上由于预编译相关命令的请求参数和返回的结果集,均采用二进制格式来封装数据 (ProtocolBinary::Resultset),体积更小,更面向底层,能直接被Mysql服务端利用,实际上是预编译是非常高效的。并且预编译一次编译、多次运行,节省了重复解析优化的时间,同时还能一定程度上防止sql注入。
预编译阶段相关的命令主要有COM_STMT_PREPARE、COM_STMT_EXECUTE、COM_STMT_FETCH、COM_STMT_CLOSE、COM_STMT_RESET、COM_STMT_SEND_LONG_DATA。其中最重要的是COM_STMT_PREPARE和COM_STMT_EXECUTE:COM_STMT_PREPARE命令用于客户端往服务端提交一个不传递真实的参数值的待预编译的SQL;COM_STMT_EXECUTE用于服务端接收参数,并执行预编译后的SQL。
4.存储程序(Stored Programs)
从5.0版本开始,关于存储程序的协议内容包括两个部分:多结果集协议(Multi-Resultset)和多语句协议(Multi-Statement),分别规定了服务器端如何存储多结果集和如何处理多重查询。
其中,多结果集协议 (Multi-Resultset)主要用于多语句或存储过程等场景。多结果集是由基本的结果集结构拼接而成,如果第一个结果集中的标识行中的status设置了SERVER_MORE_RESULTS_EXISTS标记位,表明是多结果集,其它结果集紧随其后。
对于多语句协议 (Multi-Statement),本文不展开解释,仅介绍两个工作中常见的应用场景,方便大家理解。

  1. 在各种Mysql的客户端程序中 (Navicat、SQLyog或者Mysql自带客户端等),我们都可以一次执行多条sql,中间用英文逗号隔开即可,就是利用了Multi-Statement功能。
  2. 在Java的数据库连接配中,如果设置了allowMultiQueries=true选项,则可以在一个Mybatis代码块中写入多个sql语句,语句间使用英文分号隔开即可。
url: jdbc:mysql://xxx.com:3306/test_db?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8

1.2 SQL执行过程

SQL执行过程分为两类:
1). 查询语句执行过程如下:查询缓存—》分析器—》优化器—》权限校验—》执行器—》引擎
2). 更新语句执行流程如下:分析器----》权限校验----》执行器—》引擎—redo log prepare—》binlog—》redo log commit
图6以Mysql Update语句为例,对SQL执行流程进行了比较清晰的展示,其他操作类型流程上类似。连接阶段在上文已经较为深入的介绍过,不再赘述。下面将聚焦在SQL的执行阶段,按顺序对执行阶段关键的步骤展开介绍。

图6 Mysql Update语句执行流程图[8]
1.2.1 缓存
Mysql的缓存主要的作用是为了提升查询的效率,缓存以key和value的哈希表形式存储,key是具体的sql语句,value是结果的集合。如果无法命中缓存,就继续走到分析器的的一步,如果命中缓存就直接返回给客户端 。由于查询缓存的失效非常频繁,如果在一个写多读少的环境中,缓存会频繁的新增和失效,优势并不明显。目前在5.6+版本中已经默认关闭了,且在8.0+版本中,缓存模块已被删除。
1.2.2 分析器
分析器的主要作用是将客户端发过来的SQL语句进行分析,这将包括预编译与解析过程。这个阶段包括两个步骤:第一步是词法分析,第二步是语法分析。
分析器会解析SQL语句的语义,并进行关键词和非关键词进行提取、解析,并组成一个解析树。具体的关键词包括不限定于以下:select/update/delete/or/in/where/group by/having/count/limit等。如果分析到语法错误,会直接给客户端抛出异常:You have an error in your SQL syntax。
比如:select * from user where userId =1234;
在分析器中就通过语义规则器将select from where这些关键词提取和匹配出来,Mysql会自动判断关键词和非关键词,将用户的匹配字段和自定义语句识别出来。这个阶段也会做一些校验:比如校验当前数据库是否存在user表,同时假如user表中不存在userId这个字段同样会报错:unknown column in field list。
1.2.3 优化器
能够进入到优化器阶段表示SQL是符合Mysql的标准语义规则的并且可以执行的。此阶段主要是进行SQL语句的优化,会根据执行计划进行最优的选择,匹配合适的索引,选择最佳的执行方案。
比如一个典型的例子是这样的:已知表T对A、B、C列建立联合索引,在进行查询的时候,SQL是:select xx where B=x and A=x and C=x。很多人会以为是用不到索引的,但其实会用到,虽然索引必须符合最左原则才能使用,但是本质上,优化器会自动将这条SQL优化为:where A=x and B=x and C=X,这种优化会为了底层能够匹配到索引,同时在这个阶段是自动按照执行计划进行预处理,mysql会计算各个执行方法的最佳时间,最终确定一条执行的sql交给最后的执行器。
1.2.4 执行器
在执行器的阶段,会调用存储引擎的API,API会触发存储引擎执行实际逻辑,并返回结果。Mysql支持的引擎可参图7,其中,最常用的是InnoDB。

图7 Mysql 引擎特性示意图[8]

参考文献
[1]https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html
[2]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_packets.html#sect_protocol_basic_packets_packet
[3]https://www.jianshu.com/p/5e6b33d8945f
[4]https://cloud.tencent.com/developer/article/1768901
[5]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_authentication_methods.html
[6]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_command_phase.html
[7]https://dev.mysql.com/doc/internals/en/
[8]https://www.cnblogs.com/wyq178/p/11576065.html
[9]Mysql技术内幕:InnoDB存储引擎 (第2版). 姜承尧
[10]MySQL运维内参:MySQL、Galera、Inception核心原理与最佳实践. 周彦伟,王竹峰,强昌金
[11]https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html
[12]https://dev.mysql.com/doc/refman/5.7/en/faqs-innodb-change-buffer.html

Mysql整体介绍(适用于5.X版本)(上)(标贝科技)相关推荐

  1. Mysql整体介绍(适用于5.X版本)(下)(标贝科技)

    标贝科技 https://ai.data-baker.com/#/?source=qwer12 填写邀请码fwwqgs,每日免费调用量还可以翻倍 Mysql整体介绍(适用于5.X版本)(下)(标贝科技 ...

  2. mysql 锁(标贝科技)

    标贝科技 https://ai.data-baker.com/#/?source=qwer12 填写邀请码fwwqgs,每日免费调用量还可以翻倍 mysql 锁 锁类型 类型 表级锁:开销小,加锁快: ...

  3. Mysql 事务(标贝科技)

    文章目录 事务 InnoDB对ACID的支持 隔离级别 不同隔离级别下读读取数据可能出现的情况 不可重复读和幻读区别 redo log (共享表空间) redo log block 刷redo log ...

  4. go-mysql-elasticsearch+mysql 同步 ElasticSearch(标贝科技)

    标贝科技 https://ai.data-baker.com/#/?source=qwer12 填写邀请码fwwqgs,每日免费调用量还可以翻倍 一.Elasticsearch:https://www ...

  5. 标贝科技|AI企业级应用榜单发布,百度、讯飞、标贝科技等50家产品上榜

    近日,由企服行业头条组织筹办的<AI企业级应用产品实力榜单>,本周已经正式对外发榜. 企服行业头条是3W集团旗下定位于企业服务行业的垂直新媒体,对关注企服领域内的新产品.新公司.新观点.新 ...

  6. mysql5.6 cmake_MySQL之基础-2 MySQL安装介绍之5.6版本Cmake安装

    一.服务器基本环境: 系统版本: [root@localhost ~]# cat /etc/redhat-release CentOS release 5.8 (Final) 系统位数: [root@ ...

  7. PHP各版本技术特性(标贝科技)

    文章目录 PHP8 JIT 流程 配置 测试 小结 match表达式 PHP7 Hugepage Hugepage简介 Hugepage配置 Opcache file cache Opcache fi ...

  8. 关闭互斥体实现微信多开,适用于现在所有版本

    关闭互斥体实现微信多开,适用于现在所有版本 上一篇文章写了一个有版本限制的多开方法,现在有了个适用于所有版本的多开方法. 只要关闭互斥体句柄就能实现多开. 就是枚举微信进程所有的句柄,找出_WeCha ...

  9. 什么是mysql的安装版本的_一:MySQL基本介绍及安装

    一:MySQL基本介绍 1 MySQL安装包版本选择,潜规则 MySQL5.6:GA 6-12个月 小版本是偶数版,奇数版一般都是测试. MySQL5.7:GA 6-12个月 小版本是偶数版,选择5. ...

最新文章

  1. B-Trees Concepts B-树介绍(都快忘了:))
  2. ubuntu下和开发板下播放音乐
  3. contract forward,菜鸟请教一个问题:the difference between forward contract and future contract...
  4. linux:tomcat写入文件失败
  5. 【PAT乙】1083 是否存在相等的差 (20分) map
  6. 虚拟机更新为阿里数据源
  7. T-SQL数据类型的细微差别(四)
  8. python离线翻译软件哪个好用_哪个翻译软件最好用?
  9. Anaconda3安装及opencv配置
  10. 底层网工、0基础、记性差,学习CCIE/HCIE,到底是啥体验?
  11. c语言程序设计基础谭成予答案,c语言程序设计基础谭成予答案
  12. 水中搬运代码2d仿真鱼_大脸猫大脸猫爱吃鱼?天生怕水的猫咪怎么会爱上吃鱼的...
  13. 面试总结-2023届安全面试题总汇
  14. Inna and Alarm Clock
  15. Qt crator警告This does noy seem to be a “Debug“ build
  16. 金华职业技术学院计算机教研室主任,机械技术系主任及教师赴金华职业技术学院走访调研...
  17. 计算机硬件故障与软件故障,计算机常见故障可分为硬件和软件故障,具体介绍...
  18. 《Adobe Illustrator CS5中文版经典教程》—第1课1.5节使用“导航器”面板
  19. 电子元件-三极管/MOS/IGBT
  20. java 仿qq登陆界面

热门文章

  1. ubuntu服务器虚拟机,ubuntu云服务器虚拟机
  2. 华为od机试真题 Java 实现【跳格子游戏】
  3. UE4控件蓝图的UI,无法在人物的头顶显示,解决办法
  4. 音频MS1808_PCM1808_CJC1808_AK5358 ADC 用于耳机、音响、故事机产品
  5. DNN反向传播推导过程
  6. [附源码]java+ssm计算机毕业设计农产品追溯系统设计与实现e59uz(源码+程序+数据库+部署)
  7. 阿里技术人分享的三本书豆瓣评分8.5分,让你的架构思维略窥门径
  8. python 使用全局变量_Python教程之全局变量用法
  9. 在c语言中定义了一个指针变量后,C语言的指针变量
  10. ubuntu内核版本回退