写点什么

MySQL 的体系结构

作者:jun
  • 2022 年 6 月 10 日
  • 本文字数:5100 字

    阅读完需:约 17 分钟

1、MySQL 的体系结构


MySQL 整体的逻辑结构可以分为 4 层,客户层、服务层、存储引擎层、数据层

客户层
  • 客户层:进行相关的连接处理、权限控制、安全处理等操作

服务层
  • 服务层负责与客户层进行连接处理、处理以及执行 SQL 语句等,主要包含连接器、查询缓存、优化器、执行器、存储引擎。触发器、视图等也在这一层

存储引擎层
  • 存储引擎层负责对数据的存储和提取,常见的存储引擎有 InnoDB、MyISAM、Memory 等,在 MySQL5.5 之后,MySQL 默认的存储引擎就是 InnoDB,InnoDB 默认使用的索引结构就是 B+树,上面的服务层就是通过 API 接口与存储引擎层进行交互的

数据层
  • 数据层系主要包括 MySQL 中存储数据的底层文件,与上层的存储引擎进行交互,是文件的物理存储层。其存储的文件主要有:日志文件、数据文件、配置文件、MySQL 的进行 pid 文件和 socket 文件等。那么一条 SQL 语句在 MySQL 的整个体系结构是如何执行的呢?

2、SQL 语句的执行过程

当向 MySQL 发送一条 SQL 语句的时候

1、客户层
  • 首先连接器与客户端进行连接、以 linux 系统为例,通过在 Mysql 服务启动成功之后通过一下命令进行数据库的登录


[root@bp18425116f0cojd1vnz ~]# mysql -uroot -pEnter password: 
复制代码


如果密码输入错误的话就会有以下提示


ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES
复制代码


如果出现 MySQL 密码忘记的情况下,可以通过以下方法进行登录


1、查询 MySQL 服务是否启动,如若启动,关闭 MySQL 服务


[root@bp18425116f0cojd1vnz ~]# ps -ef |grep mysqlroot       87531       1  0 Feb09 ?        00:00:00 /bin/sh /www/server/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --datadir=/www/server/data --pid-file=/www/server/data/bp18425116f0cojd1vnz.pid --sql-mode=NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTIONmysql      88147   87531  0 Feb09 ?        00:43:28 /www/server/mysql/bin/mysqld --defaults-file=/etc/my.cnf --basedir=/www/server/mysql --datadir=/www/server/data --plugin-dir=/www/server/mysql/lib/plugin --user=mysql --sql-mode=NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION --log-error=bp18425116f0cojd1vnz.err --open-files-limit=65535 --pid-file=/www/server/data/bp18425116f0cojd1vnz.pid --socket=/tmp/mysql.sock --port=3306root     2725702 2724782  0 14:35 pts/0    00:00:00 grep --color=auto mysql
复制代码


2、关闭 MySQL 服务


[root@bp18425116f0cojd1vnz ~]# systemctl stop mysql[root@bp18425116f0cojd1vnz ~]# systemctl status mysql● mysqld.service - LSB: start and stop MySQL   Loaded: loaded (/etc/rc.d/init.d/mysqld; generated)   Active: inactive (dead) since Thu 2022-06-09 14:36:55 CST; 2s ago     Docs: man:systemd-sysv-generator(8)  Process: 2725788 ExecStop=/etc/rc.d/init.d/mysqld stop (code=exited, status=0/SUCCESS)
Feb 09 14:30:10 bp18425116f0cojd1vnz systemd[1]: Starting LSB: start and stop MySQL...Feb 09 14:30:11 bp18425116f0cojd1vnz mysqld[1174]: /etc/rc.d/init.d/mysqld: line 244: my_print_defaults: command not foundFeb 09 14:30:11 bp18425116f0cojd1vnz mysqld[1174]: /etc/rc.d/init.d/mysqld: line 265: cd: /www/server/mysql: No such file or directoryFeb 09 14:30:11 bp18425116f0cojd1vnz mysqld[1174]: Starting MySQLCouldn't find MySQL server (/www/server/mysql/bin/mysqld_safe)[FAILED]Feb 09 14:30:11 bp18425116f0cojd1vnz systemd[1]: Started LSB: start and stop MySQL.Jun 09 14:36:52 bp18425116f0cojd1vnz systemd[1]: Stopping LSB: start and stop MySQL...Jun 09 14:36:55 bp18425116f0cojd1vnz mysqld[2725788]: Shutting down MySQL..[ OK ]Jun 09 14:36:55 bp18425116f0cojd1vnz systemd[1]: mysqld.service: Succeeded.Jun 09 14:36:55 bp18425116f0cojd1vnz systemd[1]: Stopped LSB: start and stop MySQL.
复制代码


3、修改 vim /etc/my.cnf


在/etc/my.cnf 添加一行 skip-grant-tables


[client]#password       = your_passwordport            = 3306socket          = /tmp/mysql.sock
[mysqld]skip-grant-tablesport = 3306socket = /tmp/mysql.sockdatadir = /www/server/datadefault_storage_engine = InnoDBperformance_schema_max_table_instances = 400table_definition_cache = 400skip-external-lockingkey_buffer_size = 32Mmax_allowed_packet = 100G
复制代码


4、重新启动 MySQL 数据库


[root@bp18425116f0cojd1vnz ~]# systemctl start mysql
复制代码


5、以免密模式登录数据库


[root@bp18425116f0cojd1vnz ~]# mysql -uroot -pEnter password: Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 1Server version: 5.6.50-log Source distribution
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
复制代码


6、登录 mysql 数据库


mysql> use mysql;Database changed
复制代码


7、修改密码


mysql> update mysql.user set authentication_string=password('your_password') where user='root';Query OK, 4 rows affected (0.01 sec)Rows matched: 4  Changed: 4  Warnings: 0
复制代码


your_password 为自己想要替换的数据库密码


8、修改 /etc/my.cf


修改/etc/my.cf 文件 去除 skip-grant-tables


9、已修改之后的密码登录数据库


[root@bp18425116f0cojd1vnz ~]# mysql -uroot -pEnter password: Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 2Server version: 5.6.50-log Source distribution
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
复制代码


当连接器与客户端通过 TCP 进行三次握手连接成功之后,就会要求用户输入密码进行登录,当输入密码无误时,客户端与服务器建立连接成功之后,连接器就会去查询出改用户的权限然后存储到查询缓存中

2、查询缓存

当客户端的查询语句为 select 查询语句的时候,如若再查询缓存里面已经查询到了结果,就会直接把查询结果返回给客户端

3、解析器

在查询缓存并没有查询到结果之后,就会走到解析器,在解析器这儿,会做如下工作


1、词法分析


词法分析会根据客户端的 SQL 语句分析出各个关键词,简单地说就是把整个 SQL 拆分为一个个的单词,然后生茶一颗词法分析树


2、语法分析


在语法分析层面会根据上面生成的词法分析树判断 SQL 语句是否符合语法规则,如果不符合,就会进行相应的提示信息


mysql> select djglfdjg from user;ERROR 1054 (42S22): Unknown column 'djglfdjg' in 'field list'
复制代码


如若在解析器执行正确之后,就会去执行相应的 SQL,走到执行器

4、SQL 执行器

在执行器这个阶段,会进行 SQL 语句的执行,主要包括以下这几个部分


1、预处理阶段


  • 在开始执行的时候,预处理阶段你对这个表有没有执行查询的权限,如若没有,就会返回相应的错误

  • 检查查询的表或者字段是否存在,如若没有,也会返回相应的错误信息


2、优化器


在优化器阶段,优化器会对 SQL 的执行顺序,使用哪个索引进行优化,确定 SQL 的执行方案,在这里会生产 explain 的执行计划比如这个语句


mysql> explain SELECT Host  FROM `user` where Host='localhost';+----+-------------+-------+------+-------------------------+---------+---------+-------+------+--------------------------+| id | select_type | table | type | possible_keys           | key     | key_len | ref   | rows | Extra                    |+----+-------------+-------+------+-------------------------+---------+---------+-------+------+--------------------------+|  1 | SIMPLE      | user  | ref  | PRIMARY,index_user_Host | PRIMARY | 180     | const |    3 | Using where; Using index |+----+-------------+-------+------+-------------------------+---------+---------+-------+------+--------------------------+1 row in set (0.00 sec)
复制代码


通过 explan 执行语句可以查询到,在执行语句时,有以下结论


  • id=1 SELECT 识别符,查询序号即为 sql 语句执行的顺序

  • select_type=SIMPLE 表示 SQL 查询语句走的是单表查询

  • table=user 输出的行所用的表

  • type=ref 显示了连接使用了哪种类别,有无使用索引,type 扫描方式由快到慢system > const > eq_ref > ref > range > index > ALLsystem:系统表,少量数据,往往不需要进行磁盘 IOconst:常量连接 eq_ref:主键索引(primary key)或者非空唯一索引(unique not null)等值扫描 ref:非主键非唯一索引等值扫描 range:范围扫描 index:索引树扫描 all:全表扫描

  • possible_keys 表示查询语句可能会用到的索引,在这里有两个,PRIMARY 表示为主键索引,index_user_Host 为另一个索引

  • key 表示在查询语句时实际用到的索引,在这里为 PRIMARY,那为什么这里只用到了 PRIMARY 这个索引呢,别急,后面会说到

  • key_len 表示使用的索引长度

  • ref 列显示使用哪个列或常数与 key 一起从表中选择行

  • rows 显示 MySQL 执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引

  • Extra 该列包含 MySQL 解决查询的详细信息,Using index 表示相应的 select 操作中使用了覆盖索引(covering index),避免访问了表的数据行,using where,表明索引被用来执行索引键值的查找 Using where 表明使用了 where 过滤 Using join buffer 使用了连接缓存 Using temporary 使用了临时表保存中间结果,mysql 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by。group by 一定要遵循所建索引的顺序与个数 using filesort,using temporary,using index 最为常见,出现前两种表示是需要优化的地方通过观察上面的执行语句,在查询时,有 2 个索引,但是只用到了 PRIMARY 这个索引,并没有用到 index_user_Host,查询表所建立的索引


mysql> show  index from mysql.user;+-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| Table | Non_unique | Key_name        | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |+-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| user  |          0 | PRIMARY         |            1 | Host        | A         |        NULL |     NULL | NULL   |      | BTREE      |         |               || user  |          0 | PRIMARY         |            2 | User        | A         |           8 |     NULL | NULL   |      | BTREE      |         |               || user  |          1 | index_user_Host |            1 | Host        | A         |        NULL |     NULL | NULL   |      | BTREE      |         |               |+-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
复制代码


该表有建立 3 个索引,查询语句 SELECT Host FROM user where Host='localhost';中查询字段为 Host ,Extra 为 Using where; Using index 表明用到了覆盖索引,也就是二级索引的 B+ 树的叶子节点的数据存储的是主键值,没有必要再索引检索磁盘 IO 来查询数据,也就是覆盖索引优化,所以并没有通过 index_user_Host 这个索引去检索数据


3、执行器


在执行器执行 SQL 语句会对权限进行校验,如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口与存储引擎层进行交互,执行 SQL 语句,并将结果返回个客户端。这里只是简单介绍,后面章节详细讲解。

发布于: 刚刚阅读数: 3
用户头像

jun

关注

还未添加个人签名 2021.04.12 加入

IT行业 后端开发

评论

发布
暂无评论
MySQL的体系结构_MySQL 数据库_jun_InfoQ写作社区