本文知识点来源于官网地址https://www.cockroachlabs.com/docs/v22.1/architecture/sql-layer.html
CRDB的SQL层向开发人员公开SQL API,将高级SQL语句转换为底层键值存储的低级读写请求,并传递给事务层。
它由以下子层组成:
一旦部署了CRDB,开发人员只需要一个到集群的连接字符串,就可以开始使用SQL语句了。
CRDB集群中的每个节点都是对称的,开发人员可以向任何节点发送请求(这意味着CRDB可以很好地与负载平衡器一起工作)。接收到请求的节点充当网关节点,它处理请求并响应客户端。
对集群的请求以SQL语句的形式到达,但数据最终以键-值(KV)对的形式写入和从存储层读取。为了处理这个问题,SQL层将SQL语句转换为KV操作计划,然后将该计划传递给事务层。
开发人员将存储在CRDB中的数据视为由行和列组成的关系结构。行和列的集合被进一步组织成表。然后将表的集合组织到数据库中。一个CRDB集群可以包含许多数据库。
CRDB提供了典型的关系特性,如约束(例如外键)。这些特性意味着应用程序开发人员可以相信数据库将确保应用程序数据的一致结构;数据验证不需要单独内置于应用程序逻辑中。
CRDB实现了大多数ANSI SQL标准来显示它的关系结构。有关CRDB支持的SQL特性的完整列表,请参阅SQL特性支持。通过SQL API,开发人员可以像通过任何SQL数据库(使用BEGIN、COMMIT等)一样访问ACID语义事务。
SQL查询通过PostgreSQL连接协议访问您的集群。通过支持许多与postgresql兼容的驱动程序和orm,使您的应用程序连接到集群变得简单。
当CRDB集群中的一个节点从客户端接收到一个SQL请求时,它将解析该语句并创建一个优化的逻辑查询计划,该计划将进一步转换为一个物理查询计划。最后,它执行物理计划。
解析
SQL查询根据我们的yacc文件(描述我们支持的语法)进行解析,每个查询的SQL版本被转换为抽象语法树(AST)。
逻辑计划
在逻辑规划阶段,AST将按照以下步骤转换为查询计划:
上面最后一步的结果是一个优化的逻辑计划。要查看基于成本的优化器生成的逻辑计划,请使用EXPLAIN (OPT)语句。
物理计划
物理计划阶段根据范围位置信息决定哪些节点将参与查询的执行。这是CRDB决定分发查询的地方,以便在数据存储位置附近执行一些计算。
更具体地说,物理计划阶段将逻辑计划期间生成的优化逻辑计划转换为物理SQL操作符的有向无环图(DAG)。可以通过运行EXPLAIN(DISTSQL)语句查看这些操作符。
因为分布层表示单个键空间的抽象,所以SQL层可以对任何节点上的任何范围执行读写操作。这允许SQL操作符在网关模式或分布式模式下的行为相同。
是否在多个节点上分发查询的决定是通过一种估计需要通过网络发送的数据量的启发式方法做出的。只需要少量行的查询在网关节点上执行。其他查询分布在多个节点上。
例如,当一个查询是分布式的时,物理计划阶段将逻辑计划中的扫描操作拆分为多个物理TableReader操作符,每个节点一个操作符包含扫描所读取的范围。剩下的逻辑操作(可能执行过滤器、连接和聚合)被调度到与tablereader相同的节点上。这使得计算的执行尽可能接近物理数据。
查询执行
物理计划的组件被发送到一个或多个节点执行。在每个节点上,CRDB生成一个逻辑处理器来计算查询的一部分。节点内部或跨节点的逻辑处理器通过逻辑数据流相互通信。查询的组合结果被发送回接收查询的第一个节点,再进一步发送到SQL客户端。
每个处理器对查询操作的标量值使用编码形式。这是一种二进制形式,与SQL中使用的形式不同。因此,必须对SQL查询中列出的值进行编码,必须对逻辑处理器之间通信的数据和从磁盘读取的数据进行解码,然后再将其发送回SQL客户端。
向量化查询执行
如果启用向量化执行,则将物理计划发送到节点,由向量化执行引擎处理。
在接收到物理计划后,向量化引擎从磁盘读取批量表数据,并将数据从行格式转换为列格式。这些批列数据存储在内存中,因此引擎可以在执行期间快速访问它们。
向量化引擎使用专门的、预编译的函数快速遍历特定于类型的列数据数组。当引擎处理每一列数据时,函数的列输出存储在内存中。
在处理了输入缓冲区中的所有数据列之后,引擎将柱状输出转换回行格式,然后将处理过的行返回到SQL接口。在完全处理完一批表数据之后,引擎将读取下面一批表数据进行处理,直到执行完查询为止。
虽然SQL查询是用可解析字符串编写的,但CRDB的底层主要是用字节处理的。这意味着在查询执行中,CRDB必须将SQL表示形式的行数据转换为字符串为字节,并将从较低层返回的字节转换为可以传递回客户端的SQL数据。
同样重要的是,对于索引列,这个字节编码保持与它所表示的数据类型相同的排序顺序。这是因为CRDB最终将数据存储在一个排序的键值映射中;以与它所代表的数据相同的顺序存储字节可以让我们有效地扫描KV数据。
然而,对于非索引列(例如,非primary KEY列),CRDB使用一种编码(称为“值编码”),它消耗较少的空间,但不保留顺序。
因为CRDB是一个分布式数据库,我们为一些查询开发了一个分布式SQL (DistSQL)优化工具,它可以显著加快涉及很多范围的查询。
在非分布式查询中,协调节点接收与查询匹配的所有行,然后对整个数据集执行任何计算。
但是,对于兼容distsql的查询,每个节点都对其包含的行进行计算,然后将结果(而不是整个行)发送到协调节点。然后,协调节点聚合来自每个节点的结果,最后向客户端返回单个响应。
这极大地减少了提交给协调节点的数据量,并利用了经过充分验证的并行计算概念,最终减少了完成复杂查询所需的时间。此外,它在已经存储数据的节点上处理数据,这使CRDB能够处理比单个节点存储空间大的行集。
为了以分布式方式运行SQL语句,我们引入了几个概念:
逻辑计划:类似于上面描述的AST/planNode树,它表示通过计算阶段的抽象(非分布式)数据流。
物理计划:从概念上讲,物理计划是逻辑计划节点到运行CRDB的物理机器的映射。逻辑计划节点根据集群拓扑进行复制和专门化。与上面的plannode一样,物理计划的这些组件在集群上调度并运行。
CRDB的模式变更,例如添加列或二级索引,使用一个协议可以允许表在模式更改期间保持在线(即能够提供读和写服务)。该协议允许集群中的不同节点在不同时间异步过渡到新的表模式。
模式变更协议将每个模式变更分解为一系列增量更改,以达到预期的效果。
例如,添加二级索引需要在开始版本和结束版本之间有两个中间模式版本,以确保在整个集群的写操作中更新索引,然后索引才可用于读取。为了确保数据库在整个模式更改过程中保持一致的状态,我们强制不变量,即集群中始终最多有两个连续的模式版本。
该方法基于论文《Online, Asynchronous Schema Change in F1》。