MySQL 是怎样运行的-第一部分

因为想整体了解 MySQL 整体的运行原理和设计原则, 认真读了一下在掘金上面的发布的小测“MySQL 是怎样运行的:从根儿上理解 MySQL”, 在已经囫囵吞枣的读完一遍之后,想在读第二遍的时候, 顺便整理一下属于自己的理解和文档。

给自己定一个小目标, 1个月内整理完自己的文档。2019-06-12开始,打个卡记录一下。

简单介绍一下整体的逻辑

第一部分: MySQL 最基础的部分, MySQL 客户端和服务端的配置信息, 以及字符集方面的知识。
第二部分: InnoDB 的数据结构
第三部分: B+ 树索引及其使用
第四部分: 数据在文件结构中的格式
第五部分: 单表查询,多表查询, 以及访问方式的选择
第六部分: MySQL 优化问题
第七部分: Buffet Pool
第八部分: 事务 redo,undo 具体流程
第九部分: 锁

第一部分

客户端及服务端部署及启动

Mysql 客户端通过提供用户名密码登录后,连接服务器程序, 发送增删改查的请求, 然后服务器响应这些请求, 从而操作它维护的数据。

MySQL 服务器进程默认为 mysqld
MySQL 客户端进程默认为 mysql

下面介绍Linux下服务端以及客户端安装启动的一些说明

  1. 安装mysql-server

    sudo apt-get install mysql-server
    

Linux 下 MySQL 服务安装路径

  • usr/bin : MySQL 的运行路径

     ├── mysql
     ├── mysql.server -> ../support-files/mysql.server
     ├── mysqladmin
     ├── mysqlbinlog
     ├── mysqlcheck
     ├── mysqld
     ├── mysqld_multi
     ├── mysqld_safe
     ├── mysqldump
     ├── mysqlimport
     ├── mysqlpump
     ... (省略其他文件)
    
  • var/lib/mysql : MySQL 数据库文件的存放路径

  • usr/lib/mysql : MySQL 的安装路径

  • etc/mysql/my.cnf : MySQL 的配置文件

  1. 查看是否安装成功并启动

    netstat -tap | grep mysql
    
  2. MySQL 在安装完成后自动启动,root账号密码为系统root密码

    mysqladmin --version        查看mysql版本
    sudo service mysql status   查看mysql状态
    sudo service mysql start    启动mysql服务
    sudo service mysql stop     停止mysql
    
  3. 开启 MySQL 远程访问,修改 MySQL 配置文件:

    vi  /etc/mysql/mysql.conf.d/mysqld.cnf
    

    把其中bind-address = 127.0.0.1注释掉

  4. 使用root登录 MySQL

    mysql -h主机名 -u用户名 -p密码
    

    各个参数意义如下:

    参数名 含义
    -h 表示服务器进程所在计算机的域名或者IP地址,连接本机可省略或填localhost或者127.0.0.1
    -u 表示用户名
    -p 表示密码

    注意

    • 连接服务器最好不要在一行命令中输入密码。 输入mysql -hlocalhost -rroot -p点击回车后会提示输入密码
    • 参数摆放顺序随意

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

CS通信过程本质就是一个进程间通信的过程, MySQL支持三种通信方式

  • TCP/IP
    MySQL 采用TCP作为CS之间的网络通信协议,服务器启动默认申请3306端口号, 客户端通过IP地址+端口号来与服务端连接。 端口号可以通过启动服务或者客户端登录时通过-P指明端口号
  • 命名管道和共享内存
    windows下独有的方式
  • Unix域套接字文件
    如果我们的服务器进程和客户端进程都运行在同一台操作系统为类Unix的机器上的话,我们可以使用Unix域套接字文件来进行进程间通信

个人感觉实际运用过程中基本全是TCP/IP这种形式实现通信。

服务器处理客户端请求

在客户端发送一个请求,到服务端处理的大致流程如下图

CS消息处理流程

  • 连接管理
    通过上面介绍的三种方式之一将客户端和服务端建立起连接

  • 解析和优化
    对文本信息经过解析,预处理以及sql语句语法的优化

    • 查询缓存,MySQL 在处理查询请求后会将刚处理过的请求和结果缓存起来,在下一次再有一模一样的请求过来的时候,直接返回缓存中的结果,如果缓存没命中,就需要进入正式的查询阶段了
    • 语法解析 判断请求的语法是否正确,解析需要查询的表,以及各种查询条件等
    • 查询优化 对请求的语句进行优化,选择成本最低的执行计划
  • 存储引擎
    MySQL服务器把数据的存储和提取操作都封装到了一个叫存储引擎的模块里,在通过上面步骤之后,根据执行计划调用存储引擎提供的API去访问真实的数据表, 获取数据返回客户端

存储引擎很多, 但是常用的只有 InnoDB(默认存储引擎), MyISAM 和 Memory

简单了解一下 InnoDB 和 MyISAM 之间的区别 https://my.oschina.net/junn/blog/183341

字符集

字符集是用来描述某个字符范围的编码规则,常用的字符集

  • ASCII
    共收录128个字符,包括空格标点符号数字大小写字母和一些不可见字符
    1个字节编码
  • ISO 8859-1(latin1)
    共收录256个字符,是在ASCII字符集的基础上又扩充了128个西欧常用字符(包括德法两国的字母)
    1个字节编码
  • GB2312
    收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母。其中收录汉字6763个,其他文字符号682个。同时这种字符集又兼容ASCII字符集
    变长编码方式:
    • 如果该字符在ASCII字符集中,则采用1字节编码。
    • 否则采用2字节编码。
  • GBK
    GBK字符集只是在收录字符范围上对GB2312字符集作了扩充,编码方式上兼容GB2312。
  • utf8
    收录地球上能想到的所有字符,而且还在不断扩充。这种字符集兼容ASCII字符集
    变长编码方式,编码一个字符需要使用1~4个字节
    utf16使用2个或4个字节编码一个字符,utf32使用4个字节编码一个字符,都属于Unicode字符集

MySQL 中的字符集和排序规则

MySQL中的utf8和utf8mb4

utf8mb3:只使用1~3个字节表示字符。MySQL中utf8是utf8mb3的别名
utf8mb4:正宗的utf8字符集,使用1~4个字节表示字符。

字符集及比较规则

MySQL 常用字符集如下表

字符集名称 Maxlen
ascii 1
latin1 1
gb2312 2
gbk 2
utf8 3
utf8mb4 4

MySQL 比较规则 实质就是排序规则,对字符串的排序方法

  • 比较规则名称以与其关联的字符集的名称开头
  • 后边紧跟着该比较规则主要作用于哪种语言,比如utf8_spanish_ci是以西班牙语的规则比较,utf8_general_ci是一种通用的比较规则。
后缀 英文释义 描述
_ai accent insensitive 不区分重音
_as accent sensitive 区分重音
_ci case insensitive 不区分大小写
_cs case sensitive 区分大小写
_bin binary 以二进制方式比较

字符集和比较规则应用

MySQL有4个级别的字符集和比较规则,分别是:

  • 服务器级别 (系统变量character_set_server, collation_server)
  • 数据库级别 (只读系统变量character_set_database, collation_database)
  • 表级别
  • 列级别
    同一个表中的不同的列也可以有不同的字符集和比较规则

创建和修改的语句中没有指明字符集和比较规则,默认使用上级的字符集和比较规则最为自己的字符集和比较规则

  • 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。
  • 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。

客户端和服务端通信中的字符集

字符集在通信中转换

系统变量 描述
character_set_client 服务器解码请求时使用的字符集
character_set_connection 服务器处理请求时会把请求字符串从character_set_client转为character_set_connection
character_set_results 服务器向客户端返回数据时使用的字符集
  • 客户端使用自己的字符集对请求编码, 发送给服务端
  • 服务端使用 character_set_client 解码,在使用 character_set_connection 转换成MySQL使用的格式
  • 根据表中列自己的格式转换格式, 读取数据
  • 将结果用 character_set_results 编码返回客户端
  • 客户端使用自己的字符集解码数据

如果客户端自己的字符集和character_set_client,character_set_results不同, 可能就会出现乱码的情况 一般情况下要使用保持这三个变量的值和客户端使用的字符集相同。

SET character_set_client = 字符集名;
SET character_set_connection = 字符集名;
SET character_set_results = 字符集名;