MySQL 学习(2)—— MySQL 体系结构与管理 | 8月更文挑战

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战mysql

1. MySQL 客户端和服务端模型

MySQL 是一种典型的 C/S 结构,C/S 结构即 客户端/服务端 模型。git

服务端程序:mysqld MySQL 自带的客户端:mysql、mysqladmin、mysqldump 等程序员

2. MySQL 的两种链接方式

经过网络链接串:TCP/IP
# mysql -uroot -p -h 127.0.0.1 -P3306
经过套接字文件,socket
# mysql -uroot -p -S /tmp/mysql.sock
复制代码

3. 实例

3.1 通俗解释

首先来讲说,数据库是作什么的。github

数据库是用来长久存储数据的,而咱们你们都知道内存只能临时存储,磁盘等才能真正存储数据。那么数据库会放在哪里呢?确定是存放在磁盘上,因此数据库其实就是磁盘上的一个文件。算法

简单的理解就是:数据库 = 磁盘上的文件。sql

既然数据库能够当作是磁盘上文件,那么咱们怎么使用数据库呢?shell

若是说咱们能够直接使用数据库,那就等价于直接使用磁盘上的文件。咱们还知道,咱们只有把磁盘上的文件读入内存中才可使用。这即是正确的数据库的使用流程。数据库

那么数据库如何把数据读入内存中呢?缓存

这个时候就须要咱们将要介绍的实例(instance)了,实例能够理解为内存结构和一组后台进程。bash

实例是用来将磁盘中的数据读入内存中,并使用数据。

3.2 专业解释

MySQL 在启动过程当中,会:

  • 启动后台守护进程(mysqld);
  • 生成工做线程;
  • 预分配内存结构供 MySQL 处理数据使用;

因此实例是:MySQL 的后台进程 + 线程 + 预分配的内存结构

而 MySQL 是单进程多线程,也就是说 MySQL 实际在系统中表现的就是一个服务进程,即进程(经过多种方法能够建立多实例,再安装一个端口号不一样的 MySQL,或者经过 workbench 来新建一个端口号不一样的服务实例等)

4. mysql 和 mysqld 的区别

  • mysqld 是 SQL 的后台程序(即 MySQL 服务器),mysqld 意思是 mysql daemon,在后台运行,监听 3306 端口,要想使用客户端程序,该程序必须运行,由于客户端经过链接服务器来访问数据库。
  • mysql 是交互式输入 SQL 语句或从文件以批处理模式执行它们的命令行工具。

5. SQL 语句引入

咱们平时在 Linux 常常会使用一些专业的命令来管理咱们操做系统中的对象,好比 touchmkidr。这些命令是 Linux 操做系统 bash shell 支持的一些功能。

对于 MySQL 也同样,MySQL 可能不会用 ls 这些命令,MySQL 也有一些专用的内置命令,用来管理数据库中的数据,咱们把这种命令称为 SQL(Structured Query Language,结构化查询语言)。

为了更方便的学习记忆,咱们将 SQL 语句分为以下经常使用的几类:

  • DML:(Data Manipulation Language,数据操做语言),由数据库管理系统(DBMS)提供,用于让用户或程序员使用,实现对数据库中数据的操做。主要包括 selectinsertupdatedeletemergeexplain plancalllock table 等语句。
  • DDL:(Data Definition Language,数据定义语言),用于定于 SQL 模式、基本表、视图和索引的建立、撤销操做,主要包含 createalterdroptruncatecommentreplace(rename) 等语句,通常不须要 commit 等事务操做。
  • DCL:(Data Control Language,数据控制语言),用于数据库受权、角色控制等管理工做。主要包含 grantrevoke 等语句。
  • TCL:(Transaction Control Language,事务控制语言),用于数据库的事务管理。主要包含 savepointrollbackcommitset transaction 等语句。

好比咱们熟悉的这条语句,在 Linux 中没法执行。

# select user,host from mysql.user;
-bash: 未预期的符号 `from' 附近有语法错误
复制代码

咱们得进入到 mysql 中才能运行。

mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+
3 rows in set (0.00 sec)
复制代码

整个过程看起来很是简单,输入语句,点击回车,而后就显示结果了。

可是咱们有没有想过,为何咱们在平时的业务开发中,好比要实现一个功能,有的人写的语句执行就快,有的人写的语句执行就慢,结果都是同样的,那么为何一个快一个慢呢?

咱们可能会想到有可能执行的慢的语句很是长、写的很复杂,是的,有多是这个缘由。

那么咱们再深刻想想,有没有多是语句在内部执行过程当中,发生了什么不可预料的操做,或者是一些操做是代价较高的操做。咱们可能不能从表面上看出问题,另外呢,也不必定 SQL 长就慢,反而有多是越长的 SQL 执行越快,越简易的语句执行的越慢。

所以,咱们不该该仅仅关注结果,而不去关注过程,就没法找到根本的缘由,接下来,咱们来学习一下,从链接数据库开始,到输入 SQL 语句,而后点击回车,而后显示结果,这个过程当中间到底发生了什么。

接下来,咱们就经过这一条查询语句,来学习一下 MySQL 详细的工做流程。

6. MySQL 内部执行过程

6.1 mysqld 程序结构

mysqld 结构,咱们分红了三层:链接层、SQL 层、存储引擎层。

MySQL 体系结构

6.2 链接层

首先一条语句多是一个用户发起的,好比 Navicat,Navicat 执行以下一条语句:

select user,host from mysql.user;
复制代码

那么首先 Navicat 得链接上 MySQL,那么它怎么链接呢?咱们以前有说过,经过 tcp/ip 或者 socket 方式进行链接。这说明链接层得支持这两种协议,并支持使用这两种协议进行链接。

而后,好比咱们使用 tcp/ip 方式链接,咱们还要输入用户名、密码、IP、端口号。假设我输入的端口号是 3307,那么可以登录吗,确定是不能够的,由于咱们配置的端口号是 3306,那说明链接层的做用还有对用户名、密码、IP、端口号等进行校验,验证合法性。

连上了以后,咱们也说了,在 MySQL 里面全部要实现的功能都须要工做的线程来提供,好比说,接收请求语句,返回结果。因此,在链接层会自动开启一个链接线程,接收语句、查看结果。咱们能够经过 show processlist 来查看链接线程状况。

mysql> show processlist;
+-----+------+-----------+------+---------+------+----------+------------------+
| Id  | User | Host      | db   | Command | Time | State    | Info             |
+-----+------+-----------+------+---------+------+----------+------------------+
| 282 | root | localhost | NULL | Query   |    0 | starting | show processlist |
+-----+------+-----------+------+---------+------+----------+------------------+
1 row in set (0.01 sec)
复制代码

而后我在另外一个终端上再启动一个 MySQL,再执行一下,发现链接线程变成了两个。

mysql> show processlist;
+-----+------+-----------+------+---------+------+----------+------------------+
| Id  | User | Host      | db   | Command | Time | State    | Info             |
+-----+------+-----------+------+---------+------+----------+------------------+
| 282 | root | localhost | NULL | Sleep   |   20 |          | NULL             |
| 286 | root | localhost | NULL | Query   |    0 | starting | show processlist |
+-----+------+-----------+------+---------+------+----------+------------------+
2 rows in set (0.00 sec)
复制代码

默认链接线程最多有 151 个,固然这个数字能够调整。没有用户请求进来都会开辟一个会话,若是这个会话 8 个小时没有动做的话,就会断开这个链接。

到这里,链接层的工做就作完了,接着把请求传递给下一层。

总结一下,链接层做用:

  1. 经过链接协议:tcp/ip 以及 socket 链接;
  2. 登陆验证:验证用户名、密码、IP、端口号等合法性;
  3. 提供链接线程:接收用户 SQL 语句以及返回结果(使用 show processlist 命令能够查看用户链接的线程状况)
  4. 将请求传递给下一层,SQL 层。

6.3 SQL 层

  1. 接收上层传送的 SQL 语句。

    SQL 层确定首先将 SQL 接收到,而后才能执行后面的操做。

  2. 语法检查:验证语句语法,判断是否知足 SQL_MODE。

    语法检查确定是必要的,若是语法检查都没用过,那确定也无法执行了。

    SQL_MODE 经常使用来解决下面几类问题:

    1. 经过设置 SQL_MODE,能够完成不一样严格程度的数据校验,有效地保障数据准确性。
    2. 经过设置 SQL_MODE 为宽松模式,来保证大多数 SQL 符合标准的 SQL 语法,这样应该用在不一样数据库之间进行迁移时,则不须要对业务的 SQL 进行较大的修改。
    3. 在不一样数据库以前进行数据迁移以前,经过设置 SQL_MODE 可使 MySQL 上的数据更方便的迁移到目标数据库中。
  3. 语义检查。判断 SQL 语句的类型。

    在 Linux 上,咱们以某个用户登陆,好比 work 用户,有些文件是不能删除的,必须切换到 root 用户才能够操做。对于 MySQL 也是如此。可是在进行权限以前,咱们能够先对 SQL 语句的类型作一下判断,而后再来判断相应的权限。

    • DDL:数据定义语言,如 create/drop/alter/
    • DCL:数据控制语言,如 grant/revoke/commit
    • DML:数据操做语言,如 insert/delete/update/select
    • DQL:数据查询语言,如 select
  4. 权限检查,检查用户对库、表是否有相应权限。

  5. 解析器:进行 SQL 语句的预处理,生成解析器(explain desc),生成多种执行方案。

    MySQL 执行语句是否能够直接执行?执行完以后是否会产生很差的效果?咱们是否须要评估一下语句的代价有多高?找到一个最快的、最合适的执行方式。

  6. 优化器:根据解析器得出的多种执行方案,进行判断,选出最优的执行计划。

    代价模型:之前 MySQL 是按照时间去衡量 SQL 语句的优劣,如今按(CPU/IO/MEM)的损耗评估性能的好坏(基于代价)。

    各个版本的优化器算法是不一样的。

  7. 执行器,选择最优的执行计划去执行 SQL 语句,产生执行的结果。

    真正运行 SQL。

    执行结果:会提供给存储引擎层一个结果说明这个查询的结果在磁盘的哪一个位置。

  8. 提供查询缓存(默认不开)。

    若是某些 SQL 一直执行,好比执行 1000 万次,那么咱们就没有必要一直执行了,咱们能够提供一个查询缓存,将请求结果放到缓存中。

  9. 提供日志记录(binlog),记录二进制日志,默认不开启。

    包括审计日志、通用日志、binlog。

6.4 存储引擎层

在 SQL 层中,执行器执行完,会得出一个结果,来展现给咱们,可是咱们的数据在哪呢,其实还在磁盘上。

Linux 上对于磁盘使用是文件系统,不能直接对磁盘进行读写。MySQL 也是如此。MySQL 将这个专门负责特殊数据读写的文件系统叫作存储引擎。(相似于 FS)。

存储引擎层的做用:

  1. 根据 SQL 的执行结果,去磁盘上找到相应数据。

  2. 找到磁盘上的 16 进制数据,再次返回 SQL 层,结构化成二维表的方式,再由链接层的专用线程返回用户,最终展示出来。

7. MySQL 逻辑存储结构

咱们能够把 MySQL 理解成一个文件系统,所以不少概念、命令能够对比 Linux 学习。下标中总结了 MySQL 和 Linux 中相似的概念。

MySQL 中概念 Linux 中概念
目录
create database account charset utf8mb4; mkdir /account
show databases; ls /
use account; cd /account
文件
列(字段)
数据行(记录) 数据行
表属性 文件属性
列属性

8. MySQL 物理存储结构

8.1 数据库

MySQL 中的库在文件系统上是使用目录来表示。咱们 MySQL 的数据存储在 /data/mysql/data 下。

首先咱们查看一下咱们的数据库。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
复制代码

而后我在 /data/mysql/data 下建立个 account 目录。

# mkdir account
复制代码

咱们再来看一下数据库。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| account            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
复制代码

能够看到多了一个 account 数据库。

8.2 表

咱们如今来看一下常见的 MyISAM 存储引擎和 InnoDB 存储引擎中数据是如何存储的。以 mysql.user 表为例。

8.2.1 MyISAM

# cd /data/mysql/data/mysql
# ls
......
-rw-r----- 1 mysql mysql   10816 1月  13 22:25 user.frm
-rw-r----- 1 mysql mysql     396 1月  14 17:21 user.MYD
-rw-r----- 1 mysql mysql    4096 1月  14 17:21 user.MYI
复制代码

对于 MyISAM 存储引擎,MySQL 用 user.frmuser.MYDuser.MYI 三张表来存储数据。

  • user.frm:存储表结构(列、属性)
  • user.MYD:存储的数据记录
  • user.MYI:存储索引

8.2.2 InnoDB

-rw-r----- 1 mysql mysql    8636 1月  13 22:25 time_zone.frm
-rw-r----- 1 mysql mysql   98304 1月  13 22:25 time_zone.ibd
复制代码

对于 InnoDB 存储引擎,MySQL 用 time_zone.frmtime_zone.ibd 两张表来存储数据。

  • time_zone.frm:存储表结构(列、属性)
  • time_zone.ibd:存储的数据记录和索引

其实对于 InnoDB 存储引擎,MySQL 还有一个文件用来存储元数据,也就是数据字典。该文件名叫 ibdata1。咱们在 /data/mysql/data 目录下。

9. InnoDB 段、区、页

通常状况下(非分区表):

  • 一个表就是一个段;
  • 一个段由多个区构成;
  • 一个区在一个页是 16k 大小的状况下,由 64 个连续的页构成,共 1M 大小;

10. 用户和权限管理

10.1 用户做用

  1. 登陆 MySQL
  2. 管理 MySQL

10.2 用户定义

用户名@'白名单',例如:root@'localhost'

10.3 用户操做

10.3.1 建立用户:

mysql> create user user2@'localhost';
mysql> exit
复制代码
# mysql -uuser2
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 307
......
复制代码

10.3.2 建立用户(带密码):

mysql> create user user3@'localhost' identified by '123';
Query OK, 0 rows affected (0.00 sec)
复制代码

10.3.3 查询用户:

mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| user1         | 10.0.0.%  |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
| user2         | localhost |
| user3         | localhost |
+---------------+-----------+
6 rows in set (0.00 sec)
复制代码

10.3.3 修改用户密码

mysql> alter user user3@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
复制代码

10.3.4 删除用户

mysql> drop user user3@'localhost';
Query OK, 0 rows affected (0.01 sec)

mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| user1         | 10.0.0.%  |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
| user2         | localhost |
+---------------+-----------+
5 rows in set (0.00 sec)
复制代码

10.4 权限管理

10.4.1 权限列表

  • ALL:全部权限

    select、insert、update、delete ......

  • with grant option:受权权限(能够给其余用户受权)

10.4.2 受权命令

grant 权限 on 做用目标 to 用户 identified 密码 with grant option;

做用目标:

  • *.*:MySQL 下全部数据库全部表。
  • account.*:account 数据库下面的全部表
  • account.t1:account 数据库下面的 t1 表

10.4.3 受权需求

  1. 建立一个管理员用户,能够经过 10 网段,管理数据库
mysql> grant all on *.* to root@'10.0.0.*' identified by '123' with grant option;
复制代码
  1. 建立一个应用用户,能够经过 10 网段,能够对 account 库下的表进行 select、insert、delete、update
mysql> grant select,insert,delete,update on account.* to user4@'10.0.0.*' identified by '123';
复制代码

10.4.4 回收权限

  • 查看权限
mysql> show grants for user4@'10.0.0.*';
+---------------------------------------------------------------------------+
| Grants for user4@10.0.0.*                                                 |
+---------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'user4'@'10.0.0.*'                                  |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `account`.* TO 'user4'@'10.0.0.*' |
+---------------------------------------------------------------------------+
2 rows in set (0.00 sec)
复制代码
  • 回收权限
mysql> revoke delete on account.* from user4@'10.0.0.*';
Query OK, 0 rows affected (0.00 sec)

mysql> show grants for user4@'10.0.0.*';
+-------------------------------------------------------------------+
| Grants for user4@10.0.0.*                                         |
+-------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'user4'@'10.0.0.*'                          |
| GRANT SELECT, INSERT, UPDATE ON `account`.* TO 'user4'@'10.0.0.*' |
+-------------------------------------------------------------------+
2 rows in set (0.00 sec)
复制代码
相关文章
相关标签/搜索