KaiwuDB 内核解析 - SQL 查询的生命周期

 一、概述

KaiwuDB 内核解析系列共分上下两部分,本文是该系列的第一部分,主要涵盖了网络协议到 SQL 执行器,解释 KaiwuDB 如何执行 SQL 查询,包括系统各个组件的执行路径(网络协议、SQL 会话管理、解析器、执行计划及优化、执行器、KV 引擎、事务管理等),目的是为各个组件的结构及其之间的关系提供一个高层次的统一视图。

下图是 KaiwuDB SQL 查询执行概览。左侧是 gateway 节点,负责接收 SQL Client 的 SQL 查询,生成查询计划(逻辑计划和物理计划),构造分布式执行引擎需要的 FlowSpec 并发送到被查询数据所在的节点。每个节点会根据接收到的 FlowSpec 构造物理计划中的算子并执行,然后把数据通过网络返回到 gateway 节点。接下来我们就详细讨论一下各个组件是如何工作的。

二、PostgreSQL Wire Protocol

SQL 查询通过 Postgres Wire 协议发送到 KaiwuDB(使用 Postgres 协议是为了与现有的客户端驱动和应用程序兼容)。这个组件实现了与 Postgres wire 协议相关的功能接口。用户连接后会首先进行鉴权,鉴权通过后,就会初始化一个循环,不断地读取 SQL 语句、执行并返回结果(通过封装 golang 的 net.Conn)。

这个协议是面向消息的(PostgreSQL 消息类型,见执行器部分):在当前连接的生命周期内,会读取一个或多个包含 SQL 语句的消息,并将其传递给 SQL 执行器执行;一旦 SQL 语句执行完毕并生成结果,就会将其序列化并返回给客户端。

PostgreSQL Wire Protocol Server 是在 KaiwuDB 启动的同时初始化的。详细的初始化流程如下图所示。首先,KaiwuDB 的 start 命令会通过 server.Start 方法调用 startServeSQL 来初始化 ServConn。ServConn 负责解析 SQL 客户端的请求、检查连接的安全性并处理连接参数,然后调用 pgServer.ServConn 方法来处理 SQL Statement。

三、SQL 执行器

KaiwuDB 使用一个端口同时处理 pg/http/grpc 三种协议。在 start 阶段,KaiwuDB 实例化 pgServer 来处理 Postgres wire 协议的请求。pgServer 会实例化 KaiwuDB 的 SQL 执行器处理用户查询。

SQL 执行器会作为生产者( Producer),持续读取用户输入并调用 parser 解析 SQL 为 statement,解析的结果会保存到 Statement buffer(StmtBuf)中。同时,还会创建一个 go routine 作为消费者(Consumer),按序处理 StmtBuf 中的 SQL statements。

SQL 执行器的具体处理流程如下图所示。首先,它会通过 serverImpl 调用 processCommandsAsync 创建一个新的 goroutine,来认证客户端连接和处理 Statement buffer(StmtBuf)中的命令(上文提到的消费者)。

其返回值是一个用来标示 goroutine 是否结束的 channel。需要注意的是,这个 channel 中的任何错误信息都会被忽略,因为期间发生的任何错误的详细信息已经通知了 SQL 客户端。processCommandsAsync 还会进行鉴权工作,如果鉴权失败,这个 goroutine 就会结束,并且会调用 cancelConn 关闭整个连接。

接下来,serverImpl 会初始化一个 for loop 来接收 SQL 客户端的输入,直到连接关闭或者发生错误。此处的 for loop 是作为生产者,首先验证 SQL Client 的权限,通过后,会根据客户端发送的消息类型调用不同的方法。

消息类型定义请参考>>https://www.postgresql.org/docs/9.4/protocol-message-formats.html

下面的章节会以 handleSimpleQuery 方法为例,来说明 SQL 执行器处理 SQL 的过程。

1. SQL 接收与解析

handleSimpleQuery 的目的是用来处理简单 SQL。首先,它会从 PostgreSQL Wire Protocol 的缓存中读取一个字符串。如果读取成功,这个字符串就会发送给 KaiwuDB 的  SQL parser(SQL 解析器)。

KaiwuDB 的解析器最初复制于 PostgresSQL,随着支持更多的 SQL 语法而逐渐增强。SQL 解析器的输出为 AST(抽象语法树)数组,每个 SQL 语句一个。AST 的节点是由 pkg/sql/sem/tree 中定义的 tree.Statement 结构组成:

Go
type Statement interface {fmt.StringerNodeFormatterStatementType() StatementType// StatementTag is a short string identifying the type of statement// (usually a single verb). This is different than the Stringer output,// which is the actual statement (including args).// TODO(dt): Currently tags are always pg-compatible in the future it// might make sense to pass a tag format specifier.StatementTag() string
}

KaiwuDB 实现了使用 tree.Statement 的子类抽象了 SQL 语句的各个子句。比如,tree.SelectClause 结构抽象了 SQL 中的 SELECT 子句,包括 SELECT 的 From 和 Where 子句。同时,AST 树中的许多部分会包含一个或多个 tree.Expr 结构,用来表示诸如 l_extendedprice * (1 - l_discount)这样的算术表达式。

Go
type SelectClause struct {Distinct    boolDistinctOn  DistinctOnExprs       SelectExprsFrom        FromWhere       *WhereGroupBy     GroupByHaving      *WhereWindow      WindowTableSelect bool
}type BinaryExpr struct {Operator    BinaryOperatorLeft, Right ExprtypeAnnotationfn *BinOp
}

SQL 解析成功后,会被添加到 Statement bufer 中等待执行器处理。

下面我们以 TPCH 中的 Q7 为例,展示一下 KaiwuDB 中 AST 的结构。

TPCH 的 Q7 是用来查询两个特定国家之间(此处为法国和德国)在某段时间内(1995-01-01 到 1996-12-31)的货物运输总价值。

SQL
SELECTsupp_nation,cust_nation,l_year, sum(volume) AS revenue
FROM (SELECTn1.n_name AS supp_nation,n2.n_name AS cust_nation,extract(year FROM l_shipdate) AS l_year,l_extendedprice * (1 - l_discount) AS volumeFROMsupplier,lineitem,orders,customer,nation n1,nation n2WHEREs_suppkey = l_suppkeyAND o_orderkey = l_orderkeyAND c_custkey = o_custkeyAND s_nationkey = n1.n_nationkeyAND c_nationkey = n2.n_nationkeyAND ((n1.n_name = 'FRANCE' AND n2.n_name = 'GERMANY')or (n1.n_name = 'GERMANY' AND n2.n_name = 'FRANCE'))AND l_shipdate BETWEEN DATE '1995-01-01' AND DATE '1996-12-31') AS shipping
GROUP BYsupp_nation,cust_nation,l_year
ORDER BYsupp_nation,cust_nation,l_year;

下图即为 KaiwuDB 中 TPCH Q7 的 AST(为了方便展示做了简化处理)。每个节点中的白色部分代表空值(nil),表示当前节点不包含该结构;紫色部分代表该结构可以展开,即指向下个子节点;绿色部分代表叶节点。

因为 Q7 是 SELECT 语句,其根节点是 tree.Statement 的子类 tree.Select。Q7 中每个 Statement 都被抽象为一个具体的节点,比如 ORDER BY 被表示为 tree.OrderBy,WHERE 子句被表示为 tree.Where 等。

2. SQL 语句执行

上文提到,SQL 执行器的消费者 goroutine 会不断地从 Statement buffer 中读取 SQL 的 AST 并执行,这个功能是通过 sqlServer.ServeConn 调用 connExecutor 的 execCmd 来实现的,其主要流程见下图。

execCmd 方法会不断地读取 stmtBuf 中的内容并执行。每个 SQL 客户端连接初始化的时候,KaiwuDB 都会初始化一个用来执行 SQL 的有限状态机(FSM),它有 5 种状态:

  • stateNoTxn – 用来处理 BEGIN 语句或隐式事务(为其开启一个新的事务)

  • stateOpen – 用来执行普通的 SQL 语句

  • stateAborted – 用来处理 ROLLBACK 语句

  • stateCommitWait – 用来处理 COMMIT 语句

  • stateInternalError – 用来处理各种错误,比如 eventNonRetriableErr, stateInternalError 等

stmtBuf 的 SQL 指令被添加到状态机后,会根据其类型分别处理。普通 SQL 被定义为 ExecStmt 类型,会通过调用 connExecutor 的 execStmt 方法运行,如上图中所示。

execStmt 方法会首先判断当前状态机的状态,如果是 BEGIN 语句,则会执行 connExecutor 的 execStmtInNoTxnState 方法创建新的事务;如果是普通的 SQL 则会调用 connExecutor 的 execStmtInOpenState 运行。

下图为 execStmtInNoTxnState 创建新事物的过程。如果当前语句是 BEGIN,则会开始一个新的事物。如果是 tree.CommitTransaction, tree.ReleaseSavepoint, tree.RollbackTransaction, tree.SetTransaction 或 tree.Savepoint 中的任何一个,则会报错;其它情况(即普通的 SQL 语句),则会转换状态机的状态到 stateOpen 并创建一个隐式事务。

事务创建成功并且状态机的状态转换为 stateOpen 后,SQL 就会进入执行阶段,这部分内容会在后续文章中详细介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/160017.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器数据恢复—Zfs文件系统下文件被误删除的如何恢复数据?

服务器故障: 一台zfs文件系统服务器,管理员误操作删除服务器上的数据。 服务器数据恢复过程: 1、将故障服务器所有磁盘编号后取出,硬件工程师检测所有硬盘后没有发现有磁盘存在硬件故障。以只读方式将全部磁盘做扇区级别的镜像备…

单链表基本操作的实现,初始化,头插,尾插,判空,获取个数,查找,删除,获取前置和后置位,清空,销毁

目录 一.单链表的设计 二.单链表的实现 三.单链表的总结 一.单链表的设计 1.单链表的结构定义: typedef struct Node{int data;//数据域struct Node* next;//后继指针}Node,*List; 2.单链表的设计示意图: 3.注意,单链表的最后一个节点的next域为NULL; 4.为什么要有一个头…

0006Java安卓程序设计-ssm基于Android的校园二手商品交易平台

文章目录 **摘** **要****目** **录**系统设计开发环境 编程技术交流、源码分享、模板分享、网课教程 🐧裙:776871563 摘 要 随着毕业季的来临以及当代大学生的消费力购买力的不断增强,我们的寝室中囤积了很多二手商品,有很多是…

智能电表和互感器一起安装有什么效果?

智能电表和互感器的普及,为用电管理提供了更为精确和便捷的方式。那么,当智能电表和互感器一起安装时,会产生怎样的"化学反应"呢?下面,小编就来为大家详细的讲解下智能电表和互感器一起安装的作用吧&#xf…

服务上千家企业,矩阵通2.0重磅上线,全链路管理新媒体矩阵

自上线以来 矩阵通已服务了上千家企业级客户 覆盖汽车、家居、媒体、金融、教育等多个行业 矩阵通1.0时代 我们以“数据”为基座打造出10功能 帮助企业轻松管理新媒体矩阵 实现账号管理、数据分析、竞对监测、 人员考核、风险监管等需求 而现在 矩阵通2.0重磅上线 新增…

Keras人工智能神经网络 Regressor 回归 神经网络搭建

前期分享了使用tensorflow来进行神经网络的回归,tensorflow构建神经网络 本期我们来使用Keras来搭建一个简单的神经网络 Keras神经网络可以用来模拟回归问题 (regression),例如给下面一组数据,用一条线来对数据进行拟合,并可以预…

ActiveMQ是什么?-九五小庞

MQ是消息中间件,是一种在分布式系统中应用程序借以传递消息的媒介,常用的有ActiveMQ,RabbitMQ,kafka。ActiveMQ是Apache下的开源项目,完全支持JMS1.1和J2EE1.4规范的JMS Provider实现。特点:1、支持多种语言…

机器学习快速入门教程 Scikit-Learn实现

机器学习是什么? 机器学习是一帮计算机科学家想让计算机像人一样思考所研发出来的计算机理论。他们曾经说过,人和计算机其实本没有差别,同样都是一大批互相连接的信息传递和存储元素所组成的系统。所以有了这样的想法,加上他们得天独厚的数学功底,机器学习的前身也就孕育而生…

Linux学习笔记之二(环境变量)

Linux learning note 1、环境变量1.1、修好PATH环境变量 1、环境变量 环境变量(environment variables)即系统运行的一些环境参数。主要的环境变量有以下这些: PATH:决定了系统查找可执行文件的目录范围。HOME:指定当前用户的主目录路径。U…

python 数据挖掘库orange3 介绍

orange3 是一个非常适合初学者的data mining library. 它让使用者通过拖拽内置的组件来形成工作流。让你不需要写任何代码就可以体验到数据挖掘和可视化的魅力。 它的桌面如下,这里我创建了 3 个节点,分别是数据集、小提琴图,散点图 其中 …

C++笔记之vector的成员函数swap()和data()

C笔记之vector的成员函数swap()和data() 标准C中的std::vector类确实有swap()和data()这两个成员函数。下面是它们的简要描述: swap(): std::vector的swap()成员函数用于交换两个向量的内容,实现了高效的交换操作,不需要复制向量的元素。这…

儿童听力损伤了,家长怎么办?

很多家长对儿童听力损伤问题存在较大误区,认为儿童除了先天性耳聋以外不会有听力问题。家长总认为孩子上课或做事不专心是因为注意力不集中、多动等问题所致,大部分家长没有意识到孩子可能出现了听力损伤问题。 儿童听力损伤主要是指因各种原因导致双耳不…