MySQL「01」初识数据库服务器

87 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第01天,点击查看活动详情

MySQL 是典型的 C/S 结构,服务端程序是 mysqld,客户端程序是 mysql。

服务端进程包括两部分内容:

  • server 层,主要包括连接器、查询缓存、解析器(词法、语法分析)、优化器和执行器,负责建立、管理连接,分析和执行 SQL 语句。
  • engine 层,主要包括各种存储引擎实现,例如 InnoDB、MyISAM、Memory 等多个实现,负责数据的存储和读取。

接下来,我们将按照上述分层来逐步了解和学习 MySQL 服务端程序。

01-服务层

01.1-连接器

故名思议,连接器负责 MySQL 客户端进程与服务端进程之间的连接管理工作。 客户端与服务端之间的连接基于 TCP 协议。

通过如下命令,我们便可以 user_name 的身份登录 host 主机上的 MySQL 服务。

mysql -h${host} -u${user_name} -p

当用户名、密码验证通过后,Server 会从权限表中查询用户的权限,并且后续的权限判断都基于此时查询到的结果。 所以,如果对用户权限进行修改,并不会影响已建立的连接,只会影响该用户后续的连接。

如何查看当前有哪些用户与服务端建立了连接呢?可以通过如下命令:

--- mysql> show processlist;
+----+--------+-----------+------------+---------+------+-------+------------------+
| Id | User   | Host      | db         | Command | Time | State | Info             |
+----+--------+-----------+------------+---------+------+-------+------------------+
| 14 | samson | localhost | SAMSONS_DB | Query   |    0 | init  | show processlist |
| 15 | samson | localhost | SAMSONS_DB | Sleep   |  300 | init  | NULL             |
+----+--------+-----------+------------+---------+------+-------+------------------+

当 Command 列为 Sleep 时,说明连接完成后未执行其他命令,连接为空闲连接,且空闲时长为 300s。 MySQL 会在连接空闲一定时间后断开连接,空闲时间配置可以通过 show variables like 'wait_timeout'; 查看,默认的空闲时间为8小时,即28800s。

也可通过命令手动断开连接,例如:

--- 断开 id=15 的空闲连接
kill connection +15;

如何查看支持的最大连接数呢?可以通过 show variables like 'max_connections'; 查看,默认值为151。 因为客户端与服务段之间通过 TCP 连接,所以这个值也会受到所在服务器的限制。

而且,MySQL 连接也跟 HTTP 连接一样,有所谓的短连接、长连接,前者指每条 SQL 都需要经历 TCP 的三次握手和四次挥手,后者指一次连接之间会执行多条 SQL。 两者各有利弊:

  • 对短连接来说,每次 SQL 都需要重新建立连接,会使执行效率较低,好处就是服务端不需要持续维护连接,节省服务器资源;
  • 对长连接来说,省去了每次都要建立连接的代价,效率会较高,但是呢服务器端需要维护连接,当连接过多时会导致 OOM 而重启。

在现代应用开发过程中,为了提高访问数据库的效率,一般都会使用数据库连接池来充分利用长连接带来的优势。 为了避免长连接占用资源的弊端,一般采用:

  • 定期断开长连接。
  • 主动重置长连接,恢复到连接刚建立时的状态。

01.2-查询缓存

用来缓存查询语句的结果,以查询语句作为 key,以语句对应的结果作为 value,若命中缓存则直接返回缓存的结果。 对于只读数据库、或者读多写少的数据库,作用比较大; 但对那些需要经常更新的数据库来说,此功能比较鸡肋。

在 MySQL 8.0版本中,此功能被删除了,所以不再深究此功能。

01.3-解析器

解析器负责解析客户端传来的 SQL 语句或其他命令。 首先,词法分析将客户端命令解析成语法树,识别出要执行的方法、表名、列名等,方便后续的语法分析; 然后,语法分析将判断前一步的语法树是否满足 SQL 语法,并在不满足时向客户端返回对应的错误。

01.4-执行 SQL

经过前面的步骤以后,接下来就是 SQL 的执行阶段。 一般来说,执行可以分为三个阶段1

  1. 预处理阶段,负责检查表或字段(列)是否存在、将 select * 语句中的 * 替换为所有列名等工作。
  2. 优化阶段,优化器根据一系列的策略选择索引等执行计划,可以通过 explain 来查看 SQL 语句的执行计划。
  3. 执行阶段,将执行计划提交到存储引擎中,并等待结果返回。

02-存储引擎层

MySQL 支持 InnoDB、MyISAM、Memory 等多个存储引擎,不同存储引擎之间共享一个 Server 层。

如何指定不同的数据存储引擎?在创建表格时可以通过 engine 关键字指定要使用的数据存储引擎,例如:

CREATE TABLE hero (
    number INT,
    name VARCHAR(100),
    country varchar(100),
    PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8;

自 MySQL 8.0开始,InnoDB 是默认的存储引擎。 InnoDB 中,以 B+ 树形式存储索引,包括聚簇索引(主键索引)、二级索引。

02.1-字符集

MySQL 中支持多种字符集,例如常见的 utf8、GBK、ASCII 等。

utf8 字符集中,每个字符需要1~4个字节表示; GBK 字符集中,每个字符需要1-2个字节表示; ASCII 字符集中,每个字符只需要1个字节表示。

02.2-行记录

每个存储引擎实现的行记录格式都不相同,InnoDB 作为最常用的存储引擎,它支持4种不同格式的行记录格式:

  • compact
  • redundant
  • dynamic
  • compressed

如何制定使用哪一种行格式呢?可以用 ROW_FORMAT=COMPACT 关键字指定,例如:

CREATE TABLE hero (
    number INT,
    name VARCHAR(100),
    country varchar(100),
    PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8 ROW_FORMAT = COMPACT ;

--- 或修改已有表格
ALTER TABLE hero ROW_FORMAT = COMPRESSED ;

行记录是理解数据引擎存储数据的重要内容之一,后面会专门的学习格式内容

02.3-数据组织方式

在 InnoDB 中,数据行以页(page)的方式组织,且内存、磁盘之间也是以页为单位传输。 页的大小为16KB。 InnoDB 中,存储数据、索引的页被称为索引页或数据页。 64 个连续页称为区(extent),大小为1MB。 256个区称为一组(group)。

02.4-索引

InnoDB 中,数据是以主键为索引的 B+ 树形式存储的,也被称为聚簇索引。 在聚簇索引形成的 B+ 树中,所有的叶子节点存储的是实际的数据,所有非叶子节点存储的是冗余的索引。

除了聚簇索引(主键),为其他列定义的索引也被称为二级索引。 根据二级索引查询主键,然后根据查询到的主键在聚簇索引中查询主键对应的行记录的过程,称为回表。

03-总结

在今天的文章中,我们从全局的角度大致了解了 MySQL 服务端程序的层次结构,主要包括服务器层、存储引擎层。 接下了我们学习了每层主要的模块及它们负责的功能。 在今后的多篇文章中我们会进一步学习各个模块的详细内容,如果对 MySQL 内容感兴趣的话,希望关注后续的文章。

refs