Databend 存储架构总览

2023-11-19

目的​​​​​​​ 

通过本篇文章带大家理解一下 Databend 的存储结构。Databend 内置的 Table 引擎为 Fuse table engine ,也是接下来要花重点篇幅要讲的。

另外,Databend 还支持外置的 Hive table 及 Icebreg Table ( 即将到来)。Fuse table 是 Databend 直接把数据存储到 S3 类对象存储上,从而让用户达到一个按需付费,无须关注存储的高可用及扩容,副本这些问题。

Hive Table 是利用 Databend 替换 Hive 的查询能力,从而减少 Hive 计算节点,起到降本增效的效果(该功能已经使用)。

Iceberg Table 正在规划中 https://github.com/datafuselabs/databend/issues/8216

Fuse Table Engine 基础概念

在 Fuse Table 中有一些基础概念先做一个解释方便更想 Databend Fuse Table 的存储结构。

1. 什么是 db_id?

这是 Databend 中的一个 internal 的标识(u64),不是暴露给用户使用,Databend 对于 create database 会在对应的 bucket/[root] 下面创建一个整数命名的目录。

2. 什么是 table_id?

这是 Databend 中的一个 internal 的标识 (u64),不是暴露给用户使用,Databend 对于 create table 会在/bucket/[root]/<db_id>/ 创建一个整数命名的目录。

3. Databend 的存 block 文件是什么?

Databend 最终存储 block 是以 Parquet 为格式存储,在存储上以表为单位,文件名为:[UUID].parquet ,存储路径为:/bucket/[root]/<db_id>/<table_id>/_b/<32 位 16 进制字符串 >_v0.parquet

如:d5ee665801a64a079a8fd2711a71c780_v0.parquet

4. Databend 中 segment 文件是什么?

Databend 中用于组织 Block 的文件。一个 segment 可以多含的 Block 块,文件是 json 格式: /bucket/[root]/<db_id>/<table_id>/_sg/<32 位 16 进制字符串 >_v1.json 。

如:3b5e1325f68e47b0bd1517ffeb888a36_v1.json

5. Snapshot 是什么?

snapshot 相当于每一个数据的一个版本号 (uuid,32 位 16 进制字符串)。每个写入动作都会有一个唯一的版本号, json 格式,内部包含对应的 segment 文件, /bucket/[root]/<db_id>/<table_id>/_ss/<32 位 16 进制字符串 >_v1.json。

如:e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json

6. Databend 支持什么索引?

Databend 目前支持三类索引:min/max index, sparse index, bloom filter index 。其中 min/max, sparse index 在 Block 的 parquet 及对应的:ss, segment 中都有存储,bloom fliter 是单独存储为 parquet 文件。

Databend 存储结构 Databend 整体上的存储结构大概如下:

/bucket/[root]/snapshot 下面有 N 多的 segment , 一个 segment 里包含至少一个 block, 最多 1000 个 block 。

存储配置Databend

存储配置

[storage]
# fs | s3 | azblob | obs
type = "s3"


# To use S3-compatible object storage, uncomment this block and set your values.
[storage.s3]
bucket = "testbucket"
root = "20221012"
endpoint_url = "url"
access_key_id = "=user"
secret_access_key = "mypassword"

上面这段配置的作用:以 s3 方式把文件存到 testbucket 下面的 20221012 目录, 最终会形成如下的结构:

其中配置中 root 可以省略。

例如:/testbucket/20221012/17818/17825 对应的是 /bucket/root/db_id/table_id 这样一个结构。

table_id 里面每个目录的意义

目录 意义
_b 用于存储数据的真正block, 以parquet 格式存储
_i_b_v2 数据本身的 bloom fliter 索引,以 parquet 格式存储
_sg 全称:segment 用于管理 block 组成,json 文件格式, 一个 sg 文件最少包含一个 block ,最多包含 1000 个 block
_ss 全称:snapshot, 用于关联一个版本对应的 segment
last_snapshot_location_hint 指向最后一个 snapshot 存储的位置

验证环境

验证1 ss/sg/_b/_i_b_v2 关系

为了分析他们的关系,这里通过一个 create database/ create table / insert 例子来看看他们是怎么生成的。

create database wubx;
use wubx;
create table tb1(id int, c1 varchar);
insert into tb1 values(1, 'databend');
show create table tb1;

最后通过 show create table 可以看到:

CREATE TABLE `tb1` (
  `id` INT,
  `c1` VARCHAR
) ENGINE=FUSE SNAPSHOT_LOCATION='17818/17825/_ss/e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json'

这里可以看到:

  • wubx 的 db_id 是:17818
  • tb1 的 table_id 是:17825
  • 对应的第一个 snapshot 文件是:17818/17825/_ss/e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json

1.查询对应的 snapshot

MySQL [wubx]> select snapshot_id, snapshot_location from fuse_snapshot('wubx','tb1')\G;
*************************** 1. row ***************************
      snapshot_id: e7ccbdcff8d54ebe9aee85d9fbb3dbcb
snapshot_location: 17818/17825/_ss/e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json
1 row in set (0.005 sec)

2.接下来我们看一下,这个 snapshot 中包含那些 segment:

MySQL [wubx]> select * from fuse_segment('wubx','tb1', 'e7ccbdcff8d54ebe9aee85d9fbb3dbcb')\G;
*************************** 1. row ***************************
     file_location: 17818/17825/_sg/3b5e1325f68e47b0bd1517ffeb888a36_v1.json
    format_version: 1
       block_count: 1
         row_count: 1
bytes_uncompressed: 28
  bytes_compressed: 296
1 row in set (0.006 sec)

从这个查询中可以看到 snapshot: e7ccbdcff8d54ebe9aee85d9fbb3dbcb 只包含一个 segment: 17818/17825/_sg/3b5e1325f68e47b0bd1517ffeb888a36_v1.json, 而这个 segment 只有一个 1 block,这个 Block 只有 1 行数据。对应的 JSON 文件:

{
    "format_version": 1,
    "blocks": [
        {
            ...
            "location": [
                "17818/17825/_b/d5ee665801a64a079a8fd2711a71c780_v0.parquet",
                0
            ],
            "bloom_filter_index_location": [
                "17818/17825/_i_b_v2/d5ee665801a64a079a8fd2711a71c780_v2.parquet",
                2
            ],
            "bloom_filter_index_size": 470,
            "compression": "Lz4Raw"
        }
    ],
    "summary": {
            ...
        }
}

原始文件较长,有兴趣的可以详细阅读一个原文件。

3.对应的 block 查询

MySQL [wubx]> select * from fuse_block('wubx','tb1')\G;
*************************** 1. row ***************************
          snapshot_id: e7ccbdcff8d54ebe9aee85d9fbb3dbcb
            timestamp: 2022-10-14 06:53:55.147359
       block_location: 17818/17825/_b/d5ee665801a64a079a8fd2711a71c780_v0.parquet
           block_size: 28
bloom_filter_location: 17818/17825/_i_b_v2/d5ee665801a64a079a8fd2711a71c780_v2.parquet
    bloom_filter_size: 470
1 row in set (0.006 sec)

验证1 总结:

  1. 任何一次写入都会生成对应的 snapshot (用于 time travel )
  2. 生成的 block 会被 Segment 引用,一个写入产生的 block 数量在小于 1000 个的情况下都会属于一个 segment 中,如果超过 1000 个 block 会生成多个 segement (这个操作太大了,就不证明了)
  3. 如果上面情况,一次 insert 也会生成:一个 snapshot , 一个 segment ,一个 block,一个 bloom fliter block

基于上面的原理:

对于 Databend 写入推荐使用批量写入,不推荐单条的 insert 做生成中的数据生成。在 Databend 海量数据写入推荐使用 copy into,streaming_load ,clickhouse http handler 这三种方法, 其中前两种吞吐能力最好。

验证2 理解 snapshot

多次重复制执行:Insert into tb1 select * from tb1;共执行 10 次,加上原来 1 次,总共会形成 11 个 snapshot:

接下来看 tb1 的 snapshot 指向:17818/17825/_ss/5a0ba62a222441d3acd2d93549e46d82_v1.json

show create table tb1;
CREATE TABLE `tb1` (
  `id` INT,
  `c1` VARCHAR
) ENGINE=FUSE SNAPSHOT_LOCATION='17818/17825/_ss/5a0ba62a222441d3acd2d93549e46d82_v1.json'

Q1:snapshot 主要用来做什么?

Databend 基于 snapshot 获取相应版本的数据,Databend 也是基于 snapshot 实现事务的 RR 隔离级别。

例如:Select count(*) from tb1;相当于:select count(*) from tb1 at(snapshot=>'5a0ba62a222441d3acd2d93549e46d82');

这个 at 语句是 time travel 的一个特性,对于 time travel 可以参考:https://databend.rs/doc/reference/sql/query-syntax/dml-at#obtaining-snapshot-id-and-timestamp

Q2:snapshot 是否可以被清理?

可以的。

清理 snapshot 命令:optimize table tb1; 或是 optimize table tb1 purge;

MySQL [wubx]> optimize table tb1;
Query OK, 0 rows affected (0.013 sec)

MySQL [wubx]> select snapshot_id, snapshot_location from fuse_snapshot('wubx','tb1');
+----------------------------------+----------------------------------------------------------+
| snapshot_id                      | snapshot_location                                        |
+----------------------------------+----------------------------------------------------------+
| 5a0ba62a222441d3acd2d93549e46d82 | 17818/17825/_ss/5a0ba62a222441d3acd2d93549e46d82_v1.json |
+----------------------------------+----------------------------------------------------------+
1 row in set (0.005 sec)

但清理后,time travel 功能需要针对后面的数据才能生效,前面的 time travel 数据已经丢掉。

Q3:是否可以创建一个不带 time travel 的表?

可以的。

Databend 支持:CREATE TRANSIENT TABLE .. 创建的表

参考:https://databend.rs/doc/reference/sql/ddl/table/ddl-create-table#create-transient-table-

该方式创建的表存在一个缺点:在高并发写入读取中,容易造成正在读取的 snapshot 被回收及报错的问题。

存储优化Tips

Q1:大量小的 block 文件,是不是可以进行合并?

可以合并的。

目前需要用户进行手工触发。

optimize table tbname compact; 

这个命令的作用:

  • 把原有的 block 块 max_threads 进行并发合并,生成一份最佳的 Block size 文件列表每个
  • thread 任务对应一个 segment 文件,超过 1000 个 block 会生成多个 segment
  • 最终生成一个 snapshot 文件

经过 Compact 的最佳的 Block 块,后续在运行 compact 动作会直接跳过。

Q2: 什么时间决定需要运行 tb 的 compact?

目前 Databend 对于 Block 判定要执行 compact 的条件:

  • 单个 block 块里行数少于 80 万行且block 小于 100M会进行合并
  • 单个 block 块超过 100万行,block 会被拆分。

可以用一个简单的条件来判断

a. Block 数量大于 max_threads* 4 倍

select count(*) from fuse_block('db','tb');

b.表里block 数据少于 100M 且行数低于80万的数量超过 100 个

select if(count(*)>100,'你需要运行compact','你的block大小非常合理') from fuse_block('db','tb') where file_size <100*1024*1024 and row_count<800000;

Q3: 当出现大量的 segment 文件,是不是需要对 segment 文件合并?

是的。

对于 segment 合并也可以引入一条简单的规则

select count(*),avg(block_count),if(avg(block_count)<500,'need compact segment','segment file is ok') from fuse_segment('db','tb','snapshot_id');

如果 segment 总数超过 1000 ,而且每个 segment 平均 block 数小于 500 需要运行:

optimize table tb compact segment; 

对于频繁写入的场景建议定期运行一下 compact segment ,这样来压缩一下 ss 及对 segemnt 文件的大小,方便 meta 信息进行缓存。

Q4:进行合并操作后文件占用空间比较大,如何释放?

Databend 是一个多版本及支持 Time travel 特性的云数仓,随着历史增长,会出现挺多的版本数据,对于存在的历史版本数据可以使用

optimize table table_name purge;

现在 purge 动作会把当前的 snapshot 之外的版本全部清理掉,造成 time travel 失效的问题。后续 purge 会支持传入 snapshot 或是时间指定清理到什么位置。

Q5:如何进行 compact 和同时清理过旧的数据 ?

optimize table table_name all;

这个命令相当于:optimize table table_name compact; optimize table table_name purge;

Q6:如何真正删除一张表?

Databend 中 Drop table 为了支持 undrop table 不会所表直正删除,如果你需要立即 Drop 一张表建议使用:

drop table table_name all;

目前需要删除一个 Database 也面临这样的问题,需要先做表的删除,再删 Database 。

关于 Databend

Databend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式数仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Databend 存储架构总览 的相关文章

  • 使用 python 从 HDFS 获取文件名列表

    这里是 Hadoop 菜鸟 我搜索了一些有关 hadoop 和 python 入门的教程 但没有取得太大成功 我还不需要使用映射器和缩减器进行任何工作 但这更多是一个访问问题 作为Hadoop集群的一部分 HDFS 上有一堆 dat 文件
  • Hadoop:处理大型序列化对象

    我正在开发一个应用程序来使用 Hadoop 框架处理 和合并 几个大型 java 序列化对象 顺序 GB 大小 Hadoop 存储将文件块分布在不同的主机上 但由于反序列化需要所有块都存在于单个主机上 因此它会极大地影响性能 我该如何处理这
  • 将 hadoop fs 路径转换为 ​​EMR 上的 hdfs:// 路径

    我想知道如何将数据从 EMR 集群的 HDFS 文件系统移动到 S3 存储桶 我认识到我可以直接在 Spark 中写入 S3 但原则上 之后执行它也应该很简单 到目前为止 我还没有发现在实践中这是正确的 AWS 文档建议s3 dist cp
  • java.io.IOException:无法获取 LocationBlock 的块长度

    我正在使用 HDP 2 1 对于集群 我遇到了以下异常 并且 MapReduce 作业因此失败 实际上 我们定期使用 Flume 版本的数据创建表 1 4 我检查了映射器尝试读取的数据文件 但我找不到任何内容 2014 11 28 00 0
  • Hadoop 安全模式恢复 - 花费太长时间!

    我有一个包含 18 个数据节点的 Hadoop 集群 我在两个多小时前重新启动了名称节点 并且名称节点仍处于安全模式 我一直在寻找为什么这可能花费太长时间 但找不到好的答案 发帖在这里 Hadoop 安全模式恢复 花费大量时间 https
  • Hive 中 Sortby 和 orderby 查询的区别

    Hive sort by and order by命令用于按排序顺序获取数据 例如 Sort by hive gt SELECT E EMP ID FROM Employee E SORT BY E empid Order by hive
  • 使用 UDF 添加文件读取添加到 Hive 资源的文件

    我想知道如何读取使用添加的 Hive 资源ADD FILE来自乌德夫 例如 Hive gt add file users temp key jks Java中的UDF可以读取这个文件吗 在 Udf 中获取此文件的路径是什么 谢谢 大卫 一旦
  • Hive ParseException - 无法识别“结束”“字符串”附近的输入

    尝试从现有 DynamoDB 表创建 Hive 表时出现以下错误 NoViableAltException 88 at org apache hadoop hive ql parse HiveParser IdentifiersParser
  • 在 Hadoop 中按文件中的值排序

    我有一个文件 其中每行包含一个字符串 然后是一个空格 然后是一个数字 例子 Line1 Word 2 Line2 Word1 8 Line3 Word2 1 我需要按降序对数字进行排序 然后将结果放入文件中 为数字分配排名 所以我的输出应该
  • Hive中group by后是否可以连接字符串字段

    我正在评估 Hive 需要在 group by 之后进行一些字符串字段连接 我找到了一个名为 concat ws 的函数 但看起来我必须显式列出所有要连接的值 我想知道是否可以在 Hive 中使用 concat ws 做这样的事情 这是一个
  • 使用 Hadoop 映射两个数据集

    假设我有两个键值数据集 数据集A和B 我们称它们为数据集A和B 我想用 B 组的数据更新 A 组中的所有数据 其中两者在键上匹配 因为我要处理如此大量的数据 所以我使用 Hadoop 进行 MapReduce 我担心的是 为了在 A 和 B
  • Sqoop mysql错误-通信链路故障

    尝试运行以下命令 sqoop import connect jdbc mysql 3306 home credit risk table bureau target dir home sqoop username root password
  • 使用 python 从 hive 读取数据时的性能问题

    我在 hive 中有一个表 其中包含 351 837 110 MB 大小 记录 我正在使用 python 读取该表并写入 sql server 在此过程中 从 hive 读取数据到 pandas dataframe 需要很长时间 当我加载整
  • Hadoop:读取ORC文件并放入RDBMS中?

    我有一个以 ORC 文件格式存储的配置单元表 我想将数据导出到 Teradata 数据库 我研究了 sqoop 但找不到导出 ORC 文件的方法 有没有办法让 sqoop 为 ORC 工作 或者有什么其他工具可以用来导出数据 Thanks
  • 消息:Hive 架构版本 1.2.0 与 Metastore 的架构版本 2.1.0 不匹配 Metastore 未升级或损坏

    环境 spark2 11 hive2 2 hadoop2 8 2 hive shell 运行成功 并且没有错误或警告 但是当运行application sh时 启动失败 usr local spark bin spark submit cl
  • Oozie SSH 操作

    Oozie SSH 操作问题 Issue 我们正在尝试在集群的特定主机上运行一些命令 我们为此选择了 SSH Action 我们面对这个 SSH 问题已经有一段时间了 这里真正的问题可能是什么 请指出解决方案 logs AUTH FAILE
  • 通过 hive 访问 maxmind 的 GeoIP-country.mmdb 数据库时出现异常

    我有一个自定义 Hive UDF 来访问 MaxmindGeoIP 国家 mmdb通过 add file pqr mmdb 添加到 Hive 资源的数据库 编译好的 UDF 添加为 add jar abc jar 当我运行 hive 查询时
  • 如何使用 Amazon 的 EMR 在 CLI 中使用自定义 jar 指定 mapred 配置和 java 选项?

    我想知道如何指定mapreduce配置 例如mapred task timeout mapred min split size等等 当使用自定义 jar 运行流作业时 当我们使用 ruby 或 python 等外部脚本语言运行时 我们可以使
  • hive 从两个数组创建映射或键/值对

    我有两个具有相同数量值的数组 它们映射为 1 1 我需要从这两个数组创建一个键 值对或映射 键 值 任何想法或提示都会有帮助 当前表结构 USA WEST NUMBER Street City 135 Pacific Irvine USA
  • Hive - 线程安全的自动递增序列号生成

    我遇到一种情况 需要将记录插入到特定的 Hive 表中 其中一列需要是自动递增的序列号 即在任何时间点都必须严格遵循 max value 1 规则 记录从许多并行的 Hive 作业插入到这个特定的表中 这些作业每天 每周 每月批量运行 现在

随机推荐

  • HJ103 Redraiment的走法

    Redraiment是走梅花桩的高手 Redraiment可以选择任意一个起点 从前到后 但只能从低处往高处的桩子走 他希望走的步数最多 你能替Redraiment研究他最多走的步数吗 示例 2 5 1 5 4 5 输出 3 说明 6个点的
  • 从零开始的ESP8266探索(07)-使用Arduino for esp8266出现的问题小结

    文章目录 问题一 现象描述 原因分析 解决方法 问题二 现象描述 原因分析 解决方法 问题三 现象描述 原因分析 解决方法 实例应用 问题一 现象描述 使用 WiFi softAP 方法建立网络 有时候很难连接上 改用 WiFi begin
  • Android - Fragment 内嵌 ViewPager ,ViewPager各个页面使用Fragment第二次进入空白界

    直接说解决办法 在activity中创建adapter时fragment管理参数用supportFragmentManager 而在fragment中创建adpater时参数用childFragmentManager分开管理 就可以了 错误
  • 人工智能数学基础--极大似然估计

    极大似然估计 极大似然估计的原理 用一张图片来说明 如下图所示 原理 极大似然估计是建立在极大似然原理的基础上的一个统计方法 是概率论在统计学中的应用 极大似然估计提供了一种给定观察数据来评估模型参数的方法 即 模型已定 参数未知 通过若干
  • 【Linux】--make/makefile--gcc/g++/gdb

    文章目录 make makefile 概念 Makefile make gcc g gdb gcc g 预处理 编译 汇编 链接 静态链接 动态链接 选项操作 gdb 总结 make makefile 概念 make是Linux下的一条指令
  • 【运维实战】1.FastDFS分布式的文件存储系统入门介绍与实践

    本章目录 0x00 基础介绍 0 前言 1 简介 2 特性 3 架构 Tracker Server Storage Server Client 4 存储策略 5 过程剖析 文件上传 Upload 文件下载 Download 文件访问 HTT
  • 一个很好的开源CRM项目

    http www sugarcrm com 还有简体中文包 是个CRM软件 PHP搞的 打算开始研究之
  • centos安装jdk,tomcat,mysql等软件

    环境列表 VMware workstation full 12 1 0 3272444 exe 虚拟机 putty exe 客户端 CentOS 7 x86 64 DVD 1708 iso centos镜像 windows7旗舰版 jdk
  • uniapp打包app后,ios端微信登录报错,login:fail [:-1]未能完成操作。(PGWXAPI错误-1。)

    报错内容 errMsg login fail 1 未能完成操作 PGWXAPI错误 1 errCode 100 code 100 报错原因 在manifest json文件 视图模式里面只有appid和 ios平台通用链接两个配置 需要在m
  • 谁能告诉我war包的作用及使用方法。。。。。。

    链接地址 http zhidao baidu com link url iliyTcmsTKb1K4gHMtWUsRIBaXglyOKIQsWwdrgvydvnaUHLe0KEoHvLVz8tLYCjZmvAebFC3srXZEbhW AV
  • Metap:希望通过利用 AI 功能来改变 Metaverse 游戏生态系统

    元宇宙是一个概念 它只会随着时间的推移和让更多的人了解后而越来越受欢迎 因此 了解元宇宙能够更好地利用这种新技术的某些项目是很重要的 能够做到这一点的 一个特殊领域 游戏世界 元宇宙与游戏的关系 将元宇宙的功能与游戏空间放在一起使用并不是一
  • 硬件接口引脚定义(持续更新)

    英文各类硬件接口定义网站 https pinouts ru conn 1 SATA接口引脚定义 2 mSATA接口引脚定义 3 各类USB接口引脚定义 引脚 功能 接线颜色 备注 1 VCC 红色 电源正极 2 Data DM 白色 数据
  • ubuntu配置环境重要网址

    ping不通百度且报错 ping www baidu com Temporary failure in name resolution 的解决方案 https blog csdn net yulei qq article details 1
  • C语言在线代码运行编译工具推荐

    C语言在线运行编译 是一款可在线编程编辑器 在编辑器上输入C语言代码 点击运行 可在线编译运行C语言 C语言代码在线运行调试 C语言在线编译 可快速在线测试您的C语言代码 在线编译C语言代码发现是否存在错误 如果代码测试通过 将会输出编译后
  • V2017+CMake+DCMTK编译安装帮助文档

    转载自https blog csdn net annjeff article details 80899762 一 前言 最近由于项目需要 开始接触DCMTK库 作为一个小白在网上一顿狂搜 看了几天的CSDN博客 终于有了一点头绪 在这个过
  • rpc、gRPC快速入门,python调用,protobuf协议

    什么是rpc grpc又是什么 什么是RPC 远程过程调用协议RPC Remote Procedure Call Protocol RPC是指远程过程调用 也就是说两台服务器A B 一个应用部署在A服务器上 想要调用B服务器上应用提供的函数
  • JavaScript 记录易错点

    1 判断是否是数组的方法 Array isArray 2 获取数组长度用属性 length 不是 length 3 数组添加或删除元素 arrayObject splice index howmany item1 itemX index 必
  • docker 部署springboot(成功、截图)

    1 新建sringboot工程并打包 2 编写Dockerfile文件 基础镜像使用java FROM openjdk 8 作者 MAINTAINER feng VOLUME 指定了临时文件目录为 tmp 其效果是在主机 var lib d
  • 出行者信息服务器,出行者信息服务系统解析.ppt

    出行者信息服务系统解析 ppt ppt 制作 陈倩 ppt 审查 侯湘怡 讲解人 张怀韧 引言 出行者信息服务系统 一 出行者信息服务系统综述 二 出行者信息系统的系统构成及结构框架 三 出行者信息系统的作用 特点与效果 四 出行者信息系统
  • Databend 存储架构总览

    目的 通过本篇文章带大家理解一下 Databend 的存储结构 Databend 内置的 Table 引擎为 Fuse table engine 也是接下来要花重点篇幅要讲的 另外 Databend 还支持外置的 Hive table 及