重新认识Mysql

181 阅读12分钟

掘金小册Mysql是怎样运行的学习笔记,写的很通透,阅读请购买支持~

Mysql的C/S架构

MySql的使用过程是许多客户端(Java程序)连接到Mysql服务器程序,发送增删改查的请求,然后服务器就响应这些请求,Mysql的服务器直接和我们储存的数据打交道,去操作这些数据 Mysql本质上是计算机的一个进程,这个代表着mysql服务器的程序被称为mysql数据库实例

Mysql的安装

自己也安过好几次了,放在这里总结下.不管是求证还是探索新知,总是官方文档最香.所以我们选择在官网安装.A Quick Guide to Using the MySQL Yum Repository,采用添加yum库的方式使其自动安装

根目录为/var/lib/mysql 可执行文件已经配到环境变量中

[root@iZ2ze38tf0alwqik6mufu7Z bin]# ll |grep mysql
-rwxr-xr-x  1 root root   19356128 Sep 20 17:23 mysql
-rwxr-xr-x  1 root root   17667760 Sep 20 17:23 mysqladmin
-rwxr-xr-x  1 root root   24180440 Sep 20 17:23 mysqlbinlog
-rwxr-xr-x  1 root root   17941472 Sep 20 17:23 mysqlcheck
-rwxr-xr-x  1 root root    5415352 Sep 20 17:23 mysql_config_editor
-rwxr-xr-x  1 root root       4389 Sep 20 17:22 mysqld_pre_systemd
-rwxr-xr-x  1 root root   18182920 Sep 20 17:23 mysqldump
-rwxr-xr-x  1 root root       7690 Sep 20 17:22 mysqldumpslow
-rwxr-xr-x  1 root root   17695592 Sep 20 17:23 mysqlimport
-rwxr-xr-x  1 root root   29044640 Sep 20 17:23 mysqlpump
-rwxr-xr-x  1 root root   17600360 Sep 20 17:23 mysql_secure_installation
-rwxr-xr-x  1 root root   17626840 Sep 20 17:23 mysqlshow
-rwxr-xr-x  1 root root   17808904 Sep 20 17:23 mysqlslap
-rwxr-xr-x  1 root root    5597256 Sep 20 17:23 mysql_ssl_rsa_setup
-rwxr-xr-x  1 root root    4571480 Sep 20 17:23 mysql_tzinfo_to_sql
-rwxr-xr-x  1 root root   20149048 Sep 20 17:23 mysql_upgrade

mysql服务端的启动

来自于官方文档 MySQL 8.0参考手册

最基本的启动(不常用)

//启动
systemctl start mysqld.service
//状态
systemctl status mysqld.service

mysqld_safe

mysqld_safe这个启动脚本,间接的调用mysqld,还会启动一个监控进程,当mysql挂了时,会重启,还可以产生错误日志输出到默认目录,如下代码

root@zhaoxu-ubuntu:/var/lib/mysql# mysqld_safe
2019-12-12T00:28:27.952823Z mysqld_safe Logging to syslog.
2019-12-12T00:28:27.955637Z mysqld_safe Logging to '/var/log/mysql/error.log'.
2019-12-12T00:28:27.957806Z mysqld_safe Directory '/var/run/mysqld' for UNIX socket file don't exists.

mysql.server

mysql.server也是一个启动脚本,它会间接的调用mysqld_safe,在调用mysql.server时在后边指定start参数就可以启动服务器程序了,就像这样:

mysql.server start
mysql.server stop

启动mysql客户端

//没有空格
mysql -h主机名  -u用户名 -p密码
参数名含义
-h表示服务器进程所在计算机的域名或者IP地址,如果服务器进程就运行在本机的话,可以省略这个参数,或者填localhost或者127.0.0.1。也可以写作 --host=主机名的形式。
-u表示用户名。也可以写作 --user=用户名的形式。
-p表示密码。也可以写作 --password=密码的形式。

小贴士: 像 h、u、p 这样名称只有一个英文字母的参数称为短形式的参数,使用时前边需要加单短划线,像 host、user、password 这样大于一个英文字母的参数称为长形式的参数,使用时前边需要加双短划线。后边会详细讨论这些参数的使用方式的

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

本质上我们的java程序是一个进程(包含许多线程),而mysql服务端是一个进程,所以客户端向服务端发送请求并得到回复本质上是一个进程间通信的过程!mysql支持下面3种进程间通信方式

TCP/IP

在真是环境中,mysql服务端的线程与客户端线程一般不在一台主机中,必须通过网络来通信,Mysql采用TCP作为服务器和客户端之间的网络通信协议

如果某个进程有需要采用TCP协议进行网络通信方面的需求,可以向操作系统申请一个端口号,网络中的其他进程可以使用IP:端口来与进程连接

mysql默认监听3306端口

//服务端启动时改变端口
mysqld -P3307
//客户端指定ip,指定端口 大写P端口,小写p密码
mysql -h127.0.0.1 -uroot -P3307 -p

命名管道和共享内存

小贴士: 命名管道和共享内存是Windows操作系统中的两种进程间通信方式

当在Windows系统下,客户端与服务端的进程间通信可以使用命名管道或共享内存

命名管道

服务端添加 --enable-named-pipe 客户端添加 --pipe或者--protocol=pipe的参数

共享内存(客户端与服务段必须在同一台主机中)

服务器添加 --shared-memory 启动server后,共享内存就成了本地客户端默认的连接方式

客户端添加(非必须) --protocol=memory参数显式的指定使用共享内存进行通信

Unix域套接字文件(要求同一台主机)

如果我们的服务器和客户端进程都在同一台操作系统为类Unix的机器上,我们可以使用Unix域套接字文件进行进程间的通信,如果我们在启动++客户端++指定主机名为localhost,或者指定了--protocol=socket的启动参数,那服务器程序和客户端程序之间可以通过Unix域套接字文件进行通信,

mysql服务器默认监听的Unix域套接字文件路径为 /tmp/mysql.sock,我们可以在启动时指定socket参数

//服务器
mysqld --socket=/tmp/a.txt
//客户端
mysql -uroot -hlocalhost --socket/tmp/a.txt -p

这样他俩就可以通过指定的socket文件进行通信

服务器处理客户请求

不管哪种进程间的通信方式,都是一样的效果,即客户端进程向服务器发送一段文本(Mysql语句),服务器进程处理后再向客户端进程发送一段文本(处理结果)

image.png

我们分步来讲

连接管理 客户端进程可以使用我们上边介绍的,TCP/IP,windows下的共享内存和命名管道,类Unix下的socket通信,连接到服务进程

每一个客户端进程连接到服务器,服务器都会创建一个线程来专门负责与这个客户端的交互,当客户端退出会与服务器断开连接,但是服务器并不会立即将与该客户端的线程销毁掉,而是缓存起来 在另一个新的客户端进行连接时,把这个缓存的线程分配给新客户端,这样起到了不频繁创建和销毁线程的效果,节省开销 从这一点我们看出,因为每一个客户端都对应一个线程,所以太多的客户端连接会严重的影响服务端性能

在客户端发起链接,需要携带主机信息,用户名密码,认证失败就会拒绝链接,另外,如果客户端和服务器不运行在同一台计算机,我们可以使用SSL的网络连接进行通信,保证数据传输的安全性

当连接建立,这个服务器线程会一直等待客户端的请求,mysql接到的请求只是一个文本消息,还需要经过各种处理

解析和优化

到现在为止mysql获取了从客户端获取的文本请求,还要经过很多的处理,比较重要的就是查询缓存,语法解析,查询优化,关系是递进的

  1. 查询缓存 如果我问你9+8×16-3×2×17的值是多少,你可能会用计算器去算一下,或者牛逼一点用心算,最终得到了结果35,如果我再问你一遍9+8×16-3×2×17的值是多少,你还用再傻呵呵的算一遍么?我们刚刚已经算过了,直接说答案就好了。MySQL服务器程序处理查询请求的过程也是这样,会把刚刚处理过的查询请求和结果缓存起来,如果下一次有一模一样的请求过来,直接从缓存中查找结果就好了,就不用再傻呵呵的去底层的表中查找了。这个查询缓存可以在不同客户端之间共享,也就是说如果客户端A刚刚查询了一个语句,而客户端B之后发送了同样的查询请求,那么客户端B的这次查询就可以直接使用查询缓存中的数据。

但是有缓存不会命中的情况,也是为了查询的正确性

  • 如果两个查询请求在任何字符上的不同(空格,注释,大小写),所以这里我们要注意mysql语句的强规范性书写,就不会缓存命中
  • 如果查询请求中,有系统函数,用户自定义变量和函数,不会被缓存,如 select now();
  • 缓存失效:MySQL的缓存系统会监测涉及到的每张表,只要该表的结构或者数据被修改,如对该表使用了INSERT、 UPDATE、DELETE、TRUNCATE TABLE、ALTER TABLE、DROP TABLE或 DROP DATABASE语句,那使用该表的所有高速缓存查询都将变为无效并从高速缓存中删除!即只要对表内容和表结构有任何修改,缓存失效

虽然查询缓存有时可以提升系统性能,但也不得不因维护这块缓存而造成一些开销,比如每次都要去查询缓存中检索,查询请求处理完需要更新查询缓存,维护该查询缓存对应的内存区域。从MySQL 5.7.20开始,不推荐使用查询缓存,并在MySQL 8.0中删除。已经删了...

  1. 语法解析 如果查询缓存没有命中,接下来就到正式的查询阶段,因为客户端请求只是一段文本,所以mysql要先对这段文本进行分析,判断请求的语法是否正确,然后从文本中将要查询的表,各种查询条件都提取出来放到mysql服务器内部使用的一些数据结构上来

这个从指定的文本中提取出我们需要的信息本质上算是一个编译过程,涉及词法解析、语法分析、语义分析等阶段,这些问题不属于我们讨论的范畴,大家只要了解在处理请求的过程中需要这个步骤就好了。

  1. 查询优化 我们自己写的mysql语句执行效率可能不是很高,mysql优化程序会对我们的语句做一些优化,如外连接转化为内连接,表达式简化,子查询转化为连接,优化的结果就是生成一个执行计划,我们可以使用EXPLAIN关键字查询执行计划
EXPLAIN select now();

存储引擎

完成了查询优化,还没有真正的去访问数据表,mysql把数据的储存和提取封装到了一个 储存引擎的模块里 我们知道表示一行一行记录组成的,但是这只是逻辑上的概念,物理上如何表示记录?怎么从表中读数据?怎么写,都是储存引擎完成的事,不同的储存引擎具体的储存结构不同,采用的算法不同

小贴士: 为什么叫引擎呢?因为这个名字更拉风~ 其实这个存储引擎以前叫做表处理器,后来可能人们觉得太土,就改成了存储引擎的叫法,它的功能就是接收上层传下来的指令,然后对表中的数据进行提取或写入操作。

按图上说,我们把连接管理,查询缓存,语法解析,查询优化这些不涉及真实数据的存储叫做Mysql server的内容,而真实数据的存储划分为储存引擎的功能,各种不同的引擎向上边的mysql server提供统一的调用接口,包含了几十个底层函数

所以mysqlserver完成了查询优化之后,只需要按照生成执行计划调用存储引擎的APi,获取到数据返回客户端

image.png

常用的存储引擎

我们最常用的就是InnoDB(具备外键支持功能的事务存储引擎)和MyISAM(主要的非事务处理存储引擎),有时会提一下Memory(置于内存的表)。其中InnoDB是MySQL默认的存储引擎,我们之后会详细唠叨这个存储引擎的各种功能

关于存储引擎的一些操作

show engines;查看当前服务器程序支持的存储引擎

//innoDB nb!
InnoDB	DEFAULT	Supports transactions, row-level locking, and foreign keys	YES	YES	YES

设置表的存储引擎

我们可以为不同的表设置不同的存储引擎

//指定引擎
mysql> CREATE TABLE engine_demo_table(
    ->     i int
    -> ) ENGINE = MyISAM;

//修改表的存储引擎

ALTER TABLE engine_demo_table ENGINE = InnoDB;

//查看建表语句 SHOW CREATE TABLE daxuread;

CREATE TABLE daxuread ( bookname char(20) DEFAULT NULL, alreadypages int(11) DEFAULT NULL, allpages int(11) DEFAULT NULL, update_time datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

可以看到默认的引擎是InnoDB