写点什么

《一条 select 语句在 TiDB Server 层都发生了什么》

  • 2022-10-28
    北京
  • 本文字数:2850 字

    阅读完需:约 9 分钟

作者: Ming 原文来源:https://tidb.net/blog/08abac12

前言

相信我们平时接触数据库,对于 select 语句那是在熟悉不过了。就比如像下面的这条语句:


// 在 t1 表中,查询 id = 1 的记录select * from t1 where id = 1;
复制代码


这条语句就是一条普通的查询语句,那当我们放到数据库执行的时候,它又经历了怎样的过程的,接下来就让我们看一下,一条 select 语句在 TiDB Server 层都发生了什么。

简介

TiDB 数据库由 PD + TiDB Server + TiKV 组成。


PD 主要负责:集群整体拓扑结构的存储 / 分配全局 ID 和事务 ID/ 生成全局 TSO 时间戳 / 收集集群信息进行调度 / 提供 TiDB Dashboard 服务

TiDB Server 主要负责:客户端的连接(MySQL 协议)/SQL 语句析、编译 / 数据转化 /SQL 语执行 / 在线 DDL 语句 /GC

TiKV 主要负责:数据持久化 / 分布式事务支持 / 副本的强一致性和高可用性 /MVCC/Coprocessor(协同处理器)

| 以上则是各个组件主要负责的功能。 | |


这次主要介绍的是 Select 语句在 TiDB Server 层都由哪些操作,接下来先让我们看一下 TiDB Server 的架构:



可以看到,我们的 TiDB Server 主要由各个模块组成,每一块的功能各不相同,结合图片与介绍,我们可以大致的对 TiDB 各个模块的功能有一个认知,接下来就根据 select 语句的执行流程,来看一看每一个模块的作用。

流程解析

1、*Protocol Layer 模块*

如果我们在 Linux 操作系统上连接 TiDB 服务,因为是兼容 mysql 的,所以我们只需要执行 mysql 的连接命令,即可连接进入数据库当中,这样我们才可以执行 sql 语句,普遍方式如下:



连接的时候,我们会需要经过 TCP 的三次握手,如果我们的服务并没有启动的话,则会收到如下报错:



当我们建立完 TCP 的连接后,我们的数据库就会先对你的用户与密码进行判断,如果用户和密码不对。就会收到 ”Access denied for user” 的报错,然后结束执行。



如果我们的账号密码没有问题,那我们就成功的进入到了数据库内,在数据库内我们的操作,基于之前获取的用户权限来进行,如果在此时管理员修改了该用户的权限,因为我们已经记录了所需权限,所以不会有问题,而是在我们重新建立连接后,权限才会进行刷新。


建立连接后,如果我们想要知道我们的数据库有多少个连接,由于 TiDB 是分布式数据库,所以我们可以通过自带的 INFORMATION_SCHEMA 下面的 cluster_processlist 查看到连接信息。


2、Parse 模块

在正式执行 SQL 查询语句之前,TiDB 会先对 SQL 语句进行解析编译,Parse 主要负责解析我们的 SQL 语句,当我们连接数据库后执行一条 select 语句,该模块会首先接收到,并将其进行一个词法分析(lex)+ 语法分析(yacc),它们的操作会将我们的查询语句进行分析,判断是否符合 TiDB 的语法,如果我们输入的语句通过判断,判断出并不符合 TiDB 的语法则会报错,如下图一样:



并且经过的时候会生成一个 AST 抽象语法数,类似如下这张图:



这里值得注意的是,语法分析只是判断是否符合 TiDB 的语法,并不会针对于表是否存在,库是否存在这些进行判断。这些判断是由 compile 模块来进行的。

3、*Compile 模块*

我们的查询语句通过 Parse 模块产生 AST 抽象语法树以后呢,就会到达 Compile 模块,首先呢,该模块会对查询语句进行合法性验证,判断是否上述说的一些类似于库 / 表是否存在等,如下:



在合法性验证结束后,会对语句进行逻辑优化 + 物理优化,逻辑优化的意思呢,就是说,会根据 SQL 层面的操作进行相关的优化,物理优化呢就是针对于数据的分布 / 数据大小来决定我们的执行方式,当我们的查询语句经历的逻辑 + 物理优化后,就会生产执行计划,我们也可以通过 explain sql 语句进行查看,来判断是否走到了预期的效果,如下:


4、*Executor 模块*

通过 Compile 模块后就会来到 Executor 模块,该模块会对我们的 SQL 语句进行判断,这个判断的意思呢,就是说它会将我们的语句进行分辨,分辨是点查还是复杂 SQL,这时候就会产生两种情况。


  1. 当 Executor 模块判断执行 SQL 是点查时,则会交给 KV 模块来进行,KV 模块会通过 TiKV Client 模块来跟 TiKV 建立连接从 RocksDB-KV 当中获取数据

  2. 当 Executor 模块判断执行 SQL 是复杂 SQL 时,则会交给 DistSQL 模块,DistSQL 模块会将复杂 SQL 进行拆分,分解成多个单表查询操作,然后在通过 TiKV Client 模块跟 TiKV 建立连接从 RocksDB-KV 当中获取数据。


值得注意的是,TiDB 的数据是转换为 Key-Value 形式来进行存储的,并且是在 TiDB Server 层来进行的。Executor 当中就会有一个将关系型数据转换为 Key-Value 的过程。

5、获取 TSO

在我们执行语句的过程中 TiDB Server 会先去 PD 获取 start.ts 与 commit.ts ,这里呢会将获取分为 6 步来完成,如下:


1、TSO 请求者先向 TiDB Server 实例的 PD Client 模块发送请求TSO2、PD Client 将收到的TSO请求转发给 PD Leader节点3、PD 接收到了PD Client发送的TSO请求后,因为无法立刻分配 TSO。于是,会先为 PD Client 返回一个异步对象 tsFuture,证明自己已经收到了请求,这个 tsFuture 你先收下,待会儿你在通过这个tsFuture来领取属于你的TSO4、PD Client 会将 PD 分配的 tsFuture 转发给 TSO 请求者,TSO 请求者收到后,会将 tsFuture 存储起来5、PD 为 TSO 请求者分配 TSO(TSO 中会携带 tsFuture 信息),PD Client 会将PD分配的 TSO 转交给 TSO 请求者6、TSO 请求者接收到 PD Client 发送过来的 TSO 后,会将其中携带的 tsFuture 信息与自己收到的 tsFuture 相比对,确定是分配给自己的 TSO
复制代码

6、获取 Region 位置信息

TiDB 是一个分布式的数据库,PD 充当了一个类似于大脑的角色,我们的查询语句,需要知道数据存放在哪,就需要通过 PD 来获得路由信息,然后才将请求发送给 TiKV。为了防止过于频繁的请求 PD 造成性能问题,TiDB Server 呢会通过缓存机制来解决此类问题,获取 Region 位置信息的流程如下:


1、TiDB Server会先去访问本地的缓存,查看是否有相应的路由信息2、两种情况,一种是有路由信息,那TiDB Server就会根据新的路由信息将请求发送给TiKV,另一种情况就是当缓存中没有相关的路由信息时候,就会去PD进行获取,在通过返回的路由信息将请求发送给TiKV3、如果,请求发送到 follower 角色了,TiKV 会返回 not leader 的错误并把谁是 leader 的信息返回给 TiDB Server,然后TiDB Server更新缓存信息。
复制代码

7、返回数据

当我们从 TiKV 当中获取到所要查询数据后,会通过 Executor 模块在通过 Protocol Layer 模块返回给用户,当返回给用户后呢,会有一个加入缓存的操作,因为其有上述说的缓存机制,至此一个 select 的查询语句的全部流程就结束了。

总结

在上述中呢,就是我们的 select 语句在 TiDB Server 层所经历的过程,值得注意的是,我们的 TiDB 还有 1 个设定就是 TiKV 的 Coprocessor:


TiKV 的 Coprocessor 又名协同处理器,它呢会帮助 TiDB 将运算下推到 TiKV 当中进行,也就是说当 TiKV 收到协同处理的请求后,会根据算子 / 数据 进行过滤 / 聚合操作,这样呢,TiDB 在收到数据之后在进行二次处理则会得出结果,大大的减轻了 TiDB 的压力。


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

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
《一条select 语句在TiDB Server层都发生了什么》_管理与运维_TiDB 社区干货传送门_InfoQ写作社区