【StoneDB join 算法分析】查询模块

数字化转型
• 阅读 478

1. 背景介绍

StoneDB 采用基于知识网格技术和列式存储引擎。该存储引擎为海量数据背景下 OLAP 应用而设计,通过列式存储数据、知识网格过滤、高效数据压缩等特性,为应用系统提供低成本和高性能的数据查询支持。
本文旨在分析 StoneDB 引擎的查询模块,包括:查询模块结构图、查询流程、知识网格、知识网格优化、优化算法。

2. StoneDB架构图

【StoneDB join 算法分析】查询模块

3. 查询模块结构图

【StoneDB join 算法分析】查询模块

SQL模块(Query Layer)

1.SQL Parser

解析器的主要作用是解析SQL语句,最终生成语法树。解析器会对SQL语句进行语法和语义分析,如果有错误,则返回相应的错误信息。检查通过后,解析器会查询缓存,如果缓存中有对应的语句和查询结果,则直接返回结果,不进行接下来的优化和执行步骤。

2.Optimizer

优化器的主要作用是对SQL语句进行优化,包括选择合适的索引,数据的读取方式,生成代价最小的执行计划。

3.Execute

执行器的主要作用是判断操作的表是否有权限,如果有权限,会根据表的存储引擎定义,调用接口去读取数据,最后返回满足条件的查询结果。

4.Filter

粗糙集过滤,找到可能包含的包。

5.DPN evaluation

根据DPN迭代判断包里面每条是否满足。

6.decompress

分片并行解压粗糙过滤后命中的包。

知识网格模块(Knowledge Grid)

知识网格是由数据包节点和知识节点组成的。由于数据包都是压缩存放的,所以数据读取解压的代价比较高,在查询中如何做到读取尽量少的数据包是提升效率的关键。知识网格正是起到了这样的一个作用,它能够有效的过滤查询中不符合条件的数据,以最小的代价定位以数据包为最小单位的数据。知识网格的数据大小只占数据总量的1%以下,通常情况下可以加载到内存中,进一步提升查询效率。

对于大部分统计、聚合性查询,StoneDB 往往只需要使用知识网格就能返回查询结果,这是因为通过知识网格可以消除或大量减少需要解压的数据包,降低 IO 消耗,提高查询响应时间和网络利用率。例如:数据包节点记录了最大值、最小值、平均值、总和、总记录数、null 值的数量,如果想对某个列做聚合运算,那么知识网格就能根据这些元数据很快的得到结果,而无需再解压访问底层的数据包。

1.数据包节点(Data Pack Node)

数据包节点也称为元数据节点(Metadata Node),因为数据包节点记录了每个数据包中列的最大值、最小值、平均值、总和、总记录数、null 值的数量、压缩方式、占用的字节数。每一个数据包节点对应一个数据包。

2.知识节点(Knowledge Node)

数据包节点的上一层是知识节点,记录了数据包之间或者列之间关系的元数据集合,比如值数据包的最小值与最大值的范围、列之间的关联关系。大部分的知识节点数据是装载数据的时候产生的,另外一部分是查询的时候产生的。

4. 查询流程图

【StoneDB join 算法分析】查询模块
查询流程大致步骤如下:

1.Client 连接

与数据库建立连接,此过程遵循 MySQL5.6、5.7 的连接协议。

2.SQL Parser

对 SQL 语句进行语法和语义分析。

解析入口:

parse_sql()

3.StoneDB Optimizer

对 SQL 语句进行优化,生成代价最小的执行计划。

优化函数:

optimize_select()

4.知识网格

StoneDB 在执行查询的时候会根据知识网络(Knowledge Grid)把 DP 分成三类:

  • 相关的 DP(Relevant Packs),满足查询条件限制的 DP
  • 不相关的 DP(Irrelevant Packs),不满足查询条件限制的 DP
  • 可疑的 DP(Suspect Packs),DP 里面的数据部分满足查询条件的限制

入口函数:

RCAttr::ApproxAnswerSize

获取DN:

Pack *get_pack(size_t i)

5.命中之后,解压相关包。

主函数:

CprsErr Decompress

6.返回结果集。

主函数:

ResultSender

5. 知识网格

5.1 知识网络总览图

【StoneDB join 算法分析】查询模块

     知识网格由数据元信息节点 (MD) 和知识节点 (KN) 组成, 通过知识网格,StoneDB 引擎无需通过传统数据索引、数据分区、预测、手动调优或特定架构等方式就能高速处理复杂的分析查询。  

5.2 元信息节点(MD)

【StoneDB join 算法分析】查询模块
数据元信息节点 (MD) 与数据节点 (DN) 之间保持 1:1 关系,元信息节点中包含了其对应数据块中数据的相关信息:

  • 数据聚合函数值 (MIN,MAX,SUM,AVG 等)。
  • 记录数量 (count)。
  • 数据中的 null 记录标记。
  • 元信息节点在数据装载的时候就会构建,MD 为数据压缩, 聚合函数即席查询等技术提供了支持。
  • 知识节点 (KN) 除了基础元数据外,还包括数据特征以及更深度的数据统信息。
  • 知识网格存储在内存中,方便快速查询。

数据结构:

struct DPN{}

获取DPN:

DPN &get_dpn

5.3 知识节点(KN)

【StoneDB join 算法分析】查询模块

  • Column Metadata 包含了该列的数据类型定义,约束条件等基础信息。

主类:

class impl
  • FieldRange 是一个标识数据节点 (DN) 中记录值范围段的标识 Map。针对数值类型的记录 (date/time, integer,decimal…),FieldRange 可以用来快速确认当前对应 DN 是否包含所需数据。FieldRange 的组成:

    • 从 MD 中获取数据块的 MAX 与 MIN,并将 MAX-MIN 划分为固定段(例如1024)。
    • 每个段中分别使用1个 bit 标识是否有记录存在与该范围内。

【StoneDB join 算法分析】查询模块

  • Char Map 是一个记录字符是否匹配的 Map。 针对字符类型的记录(char,varchar等),CharMap 可以快速确定当前 DP 是否包含所需数据。

    • 统计当前 DN 内,1-64 长度中 ASCII 字符是否存在的标识值。
    • 字符检索时,按照字符顺序,依次对比字符标示值即可知道该 DN 是否包含匹配数据。

【StoneDB join 算法分析】查询模块

  • join nodes

【StoneDB join 算法分析】查询模块

  • 在 Join 查询时自动创建,以关系位图的形式,存储 Join 操作中关联 DataNode 的信息。
  • 存储在 Session 中,仅对当前 Client 生效。
  • 显著提高Join查询性能。减少无效 DN 扫描,避免无用 IO 的产生。
  • distributions

    • 统计当前 Column 中各记录的值分布信息。
    • 基于统计信息,和粗糙集 (RoughSet) 计算,提供近似查询支持 (Approximate Query)。

【StoneDB join 算法分析】查询模块

6 知识网格优化器

对于来自客户端的请求,首先由查询优化器进行基于知识网格的优化,产生执行计划后再交给执行引擎去处理。
下图为执行流程:
【StoneDB join 算法分析】查询模块

  • 基于知识网格中的信息进行粗燥集(Rough Set)构建, 并确定此次请求所需使用到的数据节点。

    • 基于 KN 和 MD ,确定查询涉及到的 DN 节点集合,并将 DN 节点归类:

      • 关联 DN 节点:满足查询条件限制的数据节点(直接读取并返回)
      • 不确定性 DN 节点: 数据节点中部分数据满足查询条件(解压后进行处理再返回).
      • 非关联 DN 节点: 与查询条件完全不相关(直接忽略).
    • 执行计划构建时, 会完全规避非关联 DN, 仅读取并解压关联 DN, 按照特定情况决定是否读取不确定的 DN。

      • 例子: 对于一个查询请求, 通过KG可以确定 3 个关联性 DN 和 1 个不确定性 DN。如果此请求包含聚合函数。此时只需要解压不确定性 DN 并计算聚合值,再结合3个关联性 DN 中 MD上的统计值即可得出结果。如果此请求需要返回具体数据, 那么无论关联性 DN 还是不确定性 DN,都需要读取数据块并解压缩,以获得结果集。
  • 如果查询请求的结果可以直接从元信息节点 (MD) 中产生(例如 count, max, min 等操作),则直接返回元信息节点中的数据,无需访问物理数据文件.
  • 查询案例1:SELECT count(*) FROM students where score < 550。

    • 通过 KG 知识,查找包含 score < 550 的数据节点(DN),此处可以看到只有 A/B/C 三个节点涉及到该查询。
    • 数据节点 A 与 B 属于关联 DN 节点, 只需直接从对应的 MD 节点中获取 count 值即可。
    • 数据节点 C 属于不确定性 DN 节点,需要读取数据块并解压, 执行函数计算后才能返回结果集。
    • 这里只有数据块C会被读取并解压,数据节点 A 与 B 并不消耗 IO 资源。

【StoneDB join 算法分析】查询模块

7. 优化算法

7.1 Comment Lookup

Comment Lookup 只能显式地使用在 char 或者 varchar 上面。Comment Lookup可以减少存储空间,提高压缩率,对 char 和 varchar 字段采用 comment lookup 可以提高查询效率。
Comment Lookup 实现机制很像位图索引,实现上利用简短的数值类型替代char字段已取得更好的查询性能和压缩比率。Comment Lookup 的使用除了对数据类型有要求,对数据也有一定的要求。一般要求数据类别的总数小于10000并且当前列的单元数量/类别数量大于10。Comment Lookup 比较适合年龄,性别,省份这一类型的字段。
Comment Lookup 使用很简单,在创建数据库表的时候如下定义即可:

act char(15) comment 'lookup',
part char(4) comment 'lookup',

7.2 join算法

StoneDB 支持 NESTED LOOP JOIN,SORT MERGE JOIN,HASH JOIN和MAP JOIN 算法。
【StoneDB join 算法分析】查询模块
StoneDB 通过 EvaluateConditionJoinWeight 评估 join 权重,根据 UpdateJoinCondition 改变 join 条件,ChooseJoinAlgorithm 选择join算法。

7.2.1 NESTED LOOP JOIN

对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择。在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于1 万不适合),要把返回子集较小表的作为外表,CBO 默认外表是驱动表 (CBO:基于成本优化),而且在内表的连接字段上一定要有索引。通过 JoinerGeneral::ExecuteOuterJoinLoop 函数进入 NESTED LOOP JOIN 计算。

7.2.2 SORT MERGE JOIN

通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。

Sort Merge join 用在没有索引,并且数据已经排序的情况。函数 JoinerSort::ExecuteJoinConditions 进入算法,Join关联过程遵循小表扫描 MarkUsedDims(dims1),大表匹配 MarkUsedDims(dims2)。

7.2 HASH JOIN

散列连接是 CBO 做大数据集连接时的常用方式,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。
这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高 I/O 的性能。通过函数 JoinerHash::ExecuteJoinConditions 进入 JoinerHash::ExecuteJoin 执行 HASH JOIN 算法,如果 ini_join_parallel>0,调用ProxyHashJoiner/ParallelHashJoiner 并行执行。

7.2.4 MAP JOIN

Map join 适用于一个大表和一个或多个小表执行 join 操作的场景。整个join过程包含 map、shuffle 和reduce 三个阶段。通常情况下,join 操作在 reduce 阶段执行表连接。map join 操作是在 map 阶段执行的,大量缩短了数据传输的时间,提升了系统资源的利用率,从而起到了优化作业的作用,并且 map join 会将指定的小表全部加载到执行 join 操作的程序的内存中,从而加快 join 的速度。

通过 JoinerMapped::ExecuteJoinConditions 进入MAP JOIN算法,根据 JoinerMapped::GenerateFunction 生产map函数,调用 map_function 的 Init 执行 map join。

点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
ClickHouse在京东流量分析的应用实践
前言ClickHouse是一款开源列式存储的分析型数据库,相较业界OLAP数据库系统,其最核心优势就是极致的查询性能。它实现了向量化执行和SIMD指令,对内存中的列式数据,一个batch调用一次SIMD指令,大幅缩短了计算耗时,带来数倍的性能提升。目前国内社区火热,各大厂也纷纷进入该技术领域的探索。引言本文主要讨论京东黄
Stella981 Stella981
3年前
Hive SQL使用过程中的奇怪现象
hive是基于Hadoop的一个数据仓库工具,用来进行数据的ETL,这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。hive能将结构化的数据文件映射为一张数据库表,并提供SQL查询功能。HiveSQL是一种类SQL语言,与关系型数据库所支持的SQL语法存在微小的差异。本文对比MySQL和Hive所支持的SQL语法,发现相同的SQL语句在
Wesley13 Wesley13
3年前
MySQL数据库表设计规范
一、数据库设计1、一般都使用INNODB存储引擎,除非读写比率<1%,才考虑使用MYISAM存储引擎;其他存储引擎请在DBA的建议下使用。2、Storedprocedure(包括存储过程,函数,触发器)对于MYSQL来说还不是很成熟,没有完善的出错记录处理,不建议使用。3、UUID(),USER()这样的
Stella981 Stella981
3年前
Nebula 架构剖析系列(二)图数据库的查询引擎设计
摘要上文(存储篇)说到数据库重要的两部分为存储和计算,本篇内容为你解读图数据库Nebula在查询引擎 QueryEngine 方面的设计实践。在Nebula中,QueryEngine是用来处理Nebula查询语言语句(nGQL)。本篇文章将带你了解NebulaQueryEngine的架构。!(https://o
Wesley13 Wesley13
3年前
mysql 执行流程解析
MySQL可以分为Server层和存储引擎层两部分Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory
Wesley13 Wesley13
3年前
Mysql索引最佳实践笔记0524
mysql5.7innodb默认存储引擎一、关于索引二、最佳实践三、避坑实践一、关于索引1.索引的作用提高查询效率数据分组、排序避免回表查询优化聚集查询用于多表join关联查询利用唯一性约束、保证数据唯一性innodb行锁实现索引的“
Wesley13 Wesley13
3年前
MySQL基础学习笔记——MyISAM存储引擎
MyISAM存储引擎MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓库和其他应用环境下最常用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务。MyISAM主要特性有:1.大文件(达到63位文件长度)在支持大文件的文件系统和操作系统上被支
Wesley13 Wesley13
3年前
mysql储存引擎
Mysql数据库常用存储引擎数据库存储引擎:是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以获得特定的功能。现在许多不同的数据库管理系统都支持多种不同的数据引擎。MySQL的核心就是插件式存储引擎。
3A网络 3A网络
2年前
StoneDB 子查询优化
StoneDB子查询优化摘要:说明如何优化exists的join查询优化器的处理核心函数:TwoDimensionalJoiner::ChooseJoinAlgorithmcppJoinAlgTy
从 SQL 查询优化技巧去看 h2 数据库查询原理 | 京东物流技术团队
本文目标是:了解查询的核心原理,对比SQL查询优化技巧在h2database中的落地实现。前提:为了贴近实际应用,本文CodeInsight基于BTree存储引擎。数据查询核心原理数据库实现查询的原理:遍历表/索引,判断是否满足where筛选条件,添加到结
京东云开发者 京东云开发者
1个月前
京东广告基于Apache Doris的冷热数据分层实践
作者:京东零售杨博文一、背景介绍京东广告围绕ApacheDoris建设广告数据存储服务,为广告主提供实时广告效果报表和多维数据分析服务。历经多年发展,积累了海量的广告数据,目前系统总数据容量接近1PB,数据行数达到18万亿行,日查询请求量8,000万次
数字化转型
数字化转型
Lv1
上有流思人,怀旧望归客。
文章
3
粉丝
0
获赞
0