Clickhouse表引擎介绍

作者:俊达

1 引擎分类

ClickHouse表引擎一共分为四个系列,分别是Log、MergeTree、Integration、Special。其中包含了两种特殊的表引擎Replicated、Distributed,功能上与其他表引擎正交,根据场景组合使用。
在这里插入图片描述

2 Log系列

Log系列表引擎功能相对简单,主要用于快速写入小表(1百万行左右的表),然后全部读出的场景。
几种Log表引擎的共性是:

数据被顺序append写到磁盘上。

不支持delete、update。

不支持index。

不支持原子性写。

insert会阻塞select操作。

它们彼此之间的区别是:

TinyLog:不支持并发读取数据文件,查询性能较差;格式简单,适合用来暂存中间数据。

StripLog:支持并发读取数据文件,查询性能比TinyLog好;将所有列存储在同一个大文件中,减少了文件个数。

Log:支持并发读取数据文件,查询性能比TinyLog好;每个列会单独存储在一个独立文件中。

3 Integration系列

该系统表引擎主要用于将外部数据导入到ClickHouse中,或者在ClickHouse中直接操作外部数据源。
Kafka:将Kafka Topic中的数据直接导入到ClickHouse。

MySQL:将Mysql作为存储引擎,直接在ClickHouse中对MySQL表进行select等操作。

JDBC/ODBC:通过指定jdbc、odbc连接串读取数据源。

HDFS:直接读取HDFS上的特定格式的数据文件;

Special系列:Special系列的表引擎,大多是为了特定场景而定制的:

Memory:将数据存储在内存中,重启后会导致数据丢失。查询性能极好,适合于对于数据持久性没有要求的1亿以下的小表。在ClickHouse中,通常用来做临时表。

Buffer:为目标表设置一个内存buffer,当buffer达到了一定条件之后会flush到磁盘。

File:直接将本地文件作为数据存储。

Null:写入数据被丢弃、读取数据为空。

4 MergeTree系列

(1)MergeTree

MergeTree表引擎主要用于海量数据分析,支持数据分区、存储有序、主键索引、稀疏索引、数据TTL等。MergeTree支持所有ClickHouse SQL语法,但是有些功能与MySQL并不一致,比如在MergeTree中主键并不用于去重。

数据TTL

1、基本语法

TTL time_col + INTERVAL ${num} [SECOND|MONTH]

目前TTL可对具体指定列级别、或者表级别进行设置,但是设置后无法取消。

2、实现原理

1)TTL处理逻辑

若表定义中设置了TTL相关设置,在数据写入时,在分区目录下会额外生成一个ttl.txt文件,该文件通过json的格式记录了当前表列级别、表级别的TTL设置,以及当前分区目录下TTL指定时间字段的最小最大值。

MergeTree 以分区目录为单位,通过 ttl.txt文件记录过期时间,并将其作为后续的 判断依据 。

每当写入一批数据时,都会基于INTERVAL表达式的计算结果为这个分区生成 ttl. txt 文件 。

只有在MergeTree合并分区时,才会触发删除 TTL过期数据的逻辑。

在选择删除的分区时,会使用贪婪算法,它的算法规则是尽可能找到会最早过期 的,同时年纪又是最老的分区(合并次数更多 , MaxBlockNum更大的分区目录) 。

如果一个分区内某一列数据因为 TTL 到期全部被删除了,那么在合并之后生成的 新分区目录中,将不会包含这个列字段的数据文件( .bin 和 .mrk)。

2)如何触发TTL

TTL默认合并频率,由参数merge_with_ttl_timeout控制

使用 optimize命令强制触发合并

-- 触发一个分区的合并
optimize TABLE table_name-- 触发所有分区的合并
optimize TABLE table_name FINAL

(2)ReplacingMergeTree

为了解决MergeTree相同主键无法去重的问题,ClickHouse提供了ReplacingMergeTree引擎,用来做去重。虽然ReplacingMergeTree提供了主键去重的能力,但是仍旧有以下限制:

在没有彻底optimize之前,可能无法达到主键去重的效果,比如部分数据已经被去重,而另外一部分数据仍旧有主键重复。

在分布式场景下,相同primary key的数据可能被sharding到不同节点上,不同shard间可能无法去重。

optimize是后台动作,无法预测具体执行时间点。

手动执行optimize在海量数据场景下要消耗大量时间,无法满足业务即时查询的需求。

ReplacingMergeTree更多被用于确保数据最终被去重,而无法保证查询过程中主键不重复。

(3)SummingMergeTree

ClickHouse通过SummingMergeTree来支持对主键列进行预先聚合。在后台Compaction时,会将主键相同的多行进行sum求和,然后使用一行数据取而代之,从而大幅度降低存储空间占用,提升聚合计算性能。值得注意的是:

ClickHouse只在后台Compaction时才会进行数据的预先聚合,而compaction的执行时机无法预测,所以可能存在部分数据已经被预先聚合、部分数据尚未被聚合的情况。因此,在执行聚合计算时,SQL中仍需要使用GROUP BY子句。

在预先聚合时,ClickHouse会对主键列之外的其他所有列进行预聚合。如果这些列是可聚合的(比如数值类型),则直接sum;如果不可聚合(比如String类型),则随机选择一个值。

通常建议将SummingMergeTree与MergeTree配合使用,使用MergeTree来存储具体明细,使用SummingMergeTree来存储预先聚合的结果加速查询。

-- 建表
CREATE TABLE summtt
(key UInt32,value UInt32
)
ENGINE = SummingMergeTree()
ORDER BY key-- 插入数据
INSERT INTO summtt Values(1,1),(1,2),(2,1)-- compaction前查询,仍存在多行
select * from summtt;
┌─key─┬─value─┐
│   11 │
│   12 │
│   21 │
└─────┴───────┘-- 通过GROUP BY进行聚合计算
SELECT key, sum(value) FROM summtt GROUP BY key
┌─key─┬─sum(value)─┐
│   21 │
│   13 │
└─────┴────────────┘-- 强制compaction
optimize table summtt final;-- compaction后查询,可以看到数据已经被预先聚合
select * from summtt;
┌─key─┬─value─┐
│   13 │
│   21 │
└─────┴───────┘-- compaction后,仍旧需要通过GROUP BY进行聚合计算
SELECT key, sum(value) FROM summtt GROUP BY key
┌─key─┬─sum(value)─┐
│   21 │
│   13 │
└─────┴────────────┘

(4)AggregatingMergeTree

AggregatingMergeTree也是预先聚合引擎的一种,用于提升聚合计算的性能。与SummingMergeTree的区别在于:SummingMergeTree对非主键列进行sum聚合,而AggregatingMergeTree则可以指定各种聚合函数。

AggregatingMergeTree的语法比较复杂,需要结合物化视图或ClickHouse的特殊数据类型AggregateFunction一起使用。在insert和select时,也有独特的写法和要求:写入时需要使用-State语法,查询时使用-Merge语法。

示例一:配合物化视图使用。

-- 建立明细表
CREATE TABLE visits
(UserID UInt64,CounterID UInt8,StartDate Date,Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;-- 对明细表建立物化视图,该物化视图对明细表进行预先聚合
-- 注意:预先聚合使用的函数分别为: sumState, uniqState。对应于写入语法<agg>-State.
CREATE MATERIALIZED VIEW visits_agg_view
ENGINE = AggregatingMergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate)
AS SELECTCounterID,StartDate,sumState(Sign)    AS Visits,uniqState(UserID) AS Users
FROM visits
GROUP BY CounterID, StartDate;-- 插入明细数据
INSERT INTO visits VALUES(0, 0, '2019-11-11', 1);
INSERT INTO visits VALUES(1, 1, '2019-11-12', 1);-- 对物化视图进行最终的聚合操作
-- 注意:使用的聚合函数为 sumMerge, uniqMerge。对应于查询语法<agg>-Merge.
SELECTStartDate,sumMerge(Visits) AS Visits,uniqMerge(Users) AS Users
FROM visits_agg_view
GROUP BY StartDate
ORDER BY StartDate;-- 普通函数 sum, uniq不再可以使用
-- 如下SQL会报错: Illegal type AggregateFunction(sum, Int8) of argument 
SELECTStartDate,sum(Visits),uniq(Users)
FROM visits_agg_view
GROUP BY StartDate
ORDER BY StartDate;

示例二:配合特殊数据类型AggregateFunction使用。

-- 建立明细表
CREATE TABLE detail_table
(   CounterID UInt8,StartDate Date,UserID UInt64
) ENGINE = MergeTree() 
PARTITION BY toYYYYMM(StartDate) 
ORDER BY (CounterID, StartDate);-- 插入明细数据
INSERT INTO detail_table VALUES(0, '2019-11-11', 1);
INSERT INTO detail_table VALUES(1, '2019-11-12', 1);-- 建立预先聚合表,
-- 注意:其中UserID一列的类型为:AggregateFunction(uniq, UInt64)
CREATE TABLE agg_table
(   CounterID UInt8,StartDate Date,UserID AggregateFunction(uniq, UInt64)
) ENGINE = AggregatingMergeTree() 
PARTITION BY toYYYYMM(StartDate) 
ORDER BY (CounterID, StartDate);-- 从明细表中读取数据,插入聚合表。
-- 注意:子查询中使用的聚合函数为 uniqState, 对应于写入语法<agg>-State
INSERT INTO agg_table
select CounterID, StartDate, uniqState(UserID)
from detail_table
group by CounterID, StartDate-- 不能使用普通insert语句向AggregatingMergeTree中插入数据。
-- 本SQL会报错:Cannot convert UInt64 to AggregateFunction(uniq, UInt64)
INSERT INTO agg_table VALUES(1, '2019-11-12', 1);-- 从聚合表中查询。
-- 注意:select中使用的聚合函数为uniqMerge,对应于查询语法<agg>-Merge
SELECT uniqMerge(UserID) AS state 
FROM agg_table 
GROUP BY CounterID, StartDate;

(5)CollapsingMergeTree

ClickHouse实现了CollapsingMergeTree来消除ReplacingMergeTree的功能限制。该引擎要求在建表语句中指定一个标记列Sign,后台Compaction时会将主键相同、Sign相反的行进行折叠,也即删除。

CollapsingMergeTree将行按照Sign的值分为两类:Sign=1的行称之为状态行,Sign=-1的行称之为取消行。

每次需要新增状态时,写入一行状态行;需要删除状态时,则写入一行取消行。

在后台Compaction时,状态行与取消行会自动做折叠(删除)处理。而尚未进行Compaction的数据,状态行与取消行同时存在。

因此为了能够达到主键折叠(删除)的目的,需要业务层进行适当改造:

执行删除操作需要写入取消行,而取消行中需要包含与原始状态行主键一样的数据(Sign列除外)。所以在应用层需要记录原始状态行的值,或者在执行删除操作前先查询数据库获取原始状态行。

由于后台Compaction时机无法预测,在发起查询时,状态行和取消行可能尚未被折叠;另外,ClickHouse无法保证primary

key相同的行落在同一个节点上,不在同一节点上的数据无法折叠。因此在进行count()、sum(col)等聚合计算时,可能会存在数据冗余的情况。为了获得正确结果,业务层需要改写SQL,将count()、sum(col)分别改写为sum(Sign)、sum(col Sign)。

CollapsingMergeTree虽然解决了主键相同的数据即时删除的问题,但是状态持续变化且多线程并行写入情况下,状态行与取消行位置可能乱序,导致无法正常折叠。

-- 建表
CREATE TABLE UAct
(UserID UInt64,PageViews UInt8,Duration UInt8,Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;-- 插入状态行,注意sign一列的值为1
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1);-- 插入一行取消行,用于抵消上述状态行。注意sign一列的值为-1,其余值与状态行一致;
-- 并且插入一行主键相同的新状态行,用来将PageViews从5更新至6,将Duration从146更新为185.
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1), (4324182021466249494, 6, 185, 1);-- 查询数据:可以看到未Compaction之前,状态行与取消行共存。
SELECT * FROM UAct;
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 43241820214662494945146-1 │
│ 432418202146624949461851 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 432418202146624949451461 │
└─────────────────────┴───────────┴──────────┴──────┘-- 为了获取正确的sum值,需要改写SQL: 
-- sum(PageViews) => sum(PageViews * Sign)、 
-- sum(Duration) => sum(Duration * Sign)
SELECTUserID,sum(PageViews * Sign) AS PageViews,sum(Duration * Sign) AS Duration
FROM UAct
GROUP BY UserID
HAVING sum(Sign) > 0;
┌──────────────UserID─┬─PageViews─┬─Duration─┐
│ 43241820214662494946185 │
└─────────────────────┴───────────┴──────────┘-- 强制后台Compaction
optimize table UAct final;-- 再次查询,可以看到状态行、取消行已经被折叠,只剩下最新的一行状态行。
select * from UAct;
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 432418202146624949461851 │
└─────────────────────┴───────────┴──────────┴──────┘

多线程并发写入下导致数据混乱的示例

-- 建表
CREATE TABLE UAct_order
(UserID UInt64,PageViews UInt8,Duration UInt8,Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;-- 先插入取消行
INSERT INTO UAct_order VALUES (4324182021466249495, 5, 146, -1);
-- 后插入状态行
INSERT INTO UAct_order VALUES (4324182021466249495, 5, 146, 1);-- 强制Compaction
optimize table UAct_order final;-- 可以看到即便Compaction之后也无法进行主键折叠: 2行数据仍旧都存在。
select * from UAct_order;
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 43241820214662494955146-1 │
│ 432418202146624949551461 │
└─────────────────────┴───────────┴──────────┴──────┘

(6)VersionedCollapsingMergeTree

为了解决CollapsingMergeTree乱序写入情况下无法正常折叠问题,VersionedCollapsingMergeTree表引擎在建表语句中新增了一列Version,用于在乱序情况下记录状态行与取消行的对应关系。主键相同,且Version相同、Sign相反的行,在Compaction时会被删除。与CollapsingMergeTree类似, 为了获得正确结果,业务层需要改写SQL,将count()、sum(col)分别改写为sum(Sign)、sum(col * Sign)。

-- 建表
CREATE TABLE UAct_version
(UserID UInt64,PageViews UInt8,Duration UInt8,Sign Int8,Version UInt8
)
ENGINE = VersionedCollapsingMergeTree(Sign, Version)
ORDER BY UserID;-- 先插入一行取消行,注意Signz=-1, Version=1
INSERT INTO UAct_version VALUES (4324182021466249494, 5, 146, -1, 1);-- 后插入一行状态行,注意Sign=1, Version=1;及一行新的状态行注意Sign=1, Version=2,将PageViews从5更新至6,将Duration从146更新为185。
INSERT INTO UAct_version VALUES (4324182021466249494, 5, 146, 1, 1),(4324182021466249494, 6, 185, 1, 2);-- 查询可以看到未compaction情况下,所有行都可见。
SELECT * FROM UAct_version;
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 43241820214662494945146-1 │
│ 432418202146624949461851 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 432418202146624949451461 │
└─────────────────────┴───────────┴──────────┴──────┘-- 为了获取正确的sum值,需要改写SQL: 
-- sum(PageViews) => sum(PageViews * Sign)、 
-- sum(Duration) => sum(Duration * Sign)
SELECTUserID,sum(PageViews * Sign) AS PageViews,sum(Duration * Sign) AS Duration
FROM UAct_version
GROUP BY UserID
HAVING sum(Sign) > 0;
┌──────────────UserID─┬─PageViews─┬─Duration─┐
│ 43241820214662494946185 │
└─────────────────────┴───────────┴──────────┘-- 强制后台Compaction
optimize table UAct_version final;-- 再次查询,可以看到即便取消行与状态行位置乱序,仍旧可以被正确折叠。
select * from UAct_version;
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494618512 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

更多技术信息请查看云掣官网https://yunche.pro/?t=yrgw

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

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

相关文章

Spring基础——使用注解开发SpringMVC

目录 配置SpringMVC的初始化信息配置ServletWebApplicationContext配置RootWebApplicationContext配置ServletContext 创建Controller控制器配置Controller响应路径接收用户传递参数接收JSON数据接收简单类型对象封装参数 接收数组类型 Restful 文章源码仓库&#xff1a;Spring…

2024年云服务器ECS价格表出炉——阿里云

2024年阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核4G服务…

Python Web开发记录 Day9:Django part3 用户管理

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、数据库准备2、用户列表3、新建用户4、编辑用…

钡铼技术R40路由器隧道通风控制及环境监测系统集成方案

一、背景介绍 随着城市化进程的加快&#xff0c;地下交通建设越来越重要。地下隧道作为城市交通的重要组成部分&#xff0c;其安全运行和环境质量直接关系到人们的出行体验和生活质量。为了保障隧道内空气的流通和质量&#xff0c;钡铼技术R40路由器通风控制及环境监测系统应运…

【SpringCloud微服务实战08】RabbitMQ 消息队列

MQ异步通信优缺点: 优点: 吞吐量提升:无需等待订阅者处理完成,响应更快速 故障隔离:服务没有直接调用,不存在级联失败问题 调用间没有阻塞,不会造成无效的资源占用 耦合度极低,每个服务都可以灵活插拔,可替换 流量削峰:不管发布事件的流量波动多大,都由Broker接收,…

如何利用百度SEO优化技巧将排到首页

拥有一个成功的网站对于企业和个人来说是至关重要的&#xff0c;在当今数字化的时代。在互联网上获得高流量和优质的访问者可能并不是一件容易的事情&#xff0c;然而。一个成功的SEO战略可以帮助你实现这一目标。需要一些特定的技巧和策略、但要在百度搜索引擎中获得较高排名。…

Selenium 自动化 —— 入门和 Hello World 实例

Selenium 是什么 Selenium 是一个用于自动化网页浏览器操作的工具&#xff0c;它支持多种浏览器和多种操作系统。主要用于测试 web 应用程序的功能&#xff0c;也可用于执行一些基本的浏览器操作任务&#xff0c;例如自动化表单填写、网页导航等。 Selenium 是一个开源项目&a…

天地图全国幼儿园数据下载与处理分析

概述 在看天地图服务资源的时候看到有个“幼儿园”的数据&#xff0c;好奇点开看了下&#xff0c;下载下来数据差看了下&#xff0c;数据质量还不错。本篇文章给大家分享一下这个数据的处理以及一些简单的统计分析结果。 数据下载 通过地址https://service.tianditu.gov.cn/…

WPF —— Grid网格布局

1 &#xff1a;Grid网格布局简介 Grid为WPF中最常用的布局容器, 作为View中的主要组成部分, 负责框架中整体的页面布局。 2&#xff1a;网格标签Grid.ColumnDef Grid.ColumnDefinitions自定义列 只能设置宽度 不能设置高度ColumnDefinition 每一个列可以设置宽度&#xff0c;…

机试:蛇形矩阵

问题描述: 代码示例: //蛇形矩阵 #include <bits/stdc.h> using namespace std;int main(){int n;cout << "输入样例" << endl; cin >> n;int k 1; for(int i 0; i < n; i){if( i %2 0){//单数行for(int j 0; j < n; j){ cout &…

Apache Paimon 的 CDC Ingestion 概述

CDC Ingestion 1&#xff09;概述 Paimon支持schema evolution将数据插入到Paimon表中&#xff0c;添加的列将实时同步到Paimon表&#xff0c;并且无需重启同步作业。 目前支持的同步方式如下&#xff1a; MySQL Synchronizing Table: 将MySQL中的一个或多个表同步到一个Pa…

网络原理(网络协议初识)

目录 1.网络通信基础 1.1IP地址 1.2端口号 1.3认识协议 1.4五元组 1.5 协议分层 2.TCP/IP五层&#xff08;或四层&#xff09;模型 2.1网络设备所在分层 2.2网络分层对应 3.封装和分用 1.网络通信基础 网络互连的目的是进行网络通信&#xff0c;也即是网络数据传输&#…

数据仓库为什么要分层建设?每一层的作用是什么?

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。为了更好地管理和利用这些数据&#xff0c;许多企业都建立了数据仓库。然而&#xff0c;数据仓库并非简单的数据存储工具&#xff0c;而是一个复杂的数据处理和分析系统。其中&#xff0c;分层建设是数据仓库设计的重…

【OpenCV实战】基于OpenCV中DNN(深度神经网络)使用OpenPose模型实现手势识别详解

一、手部关键点检测 如图所示,为我们的手部关键点所在位置。第一步,我们需要检测手部21个关键点。我们使用深度神经网络DNN模块来完成这件事。通过使用DNN模块可以检测出手部21个关键点作为结果输出,具体请看源码。 二,openpose手势识别模型 OpenPose的原理基于卷积神经网…

【计算机图形学】End-to-End Affordance Learning for Robotic Manipulation

对RLAfford&#xff1a;End-to-End Affordance Learning for Robotic Manipulation的简单理解 1. 为什么要做这件事 在交互环境中学习如何操纵3D物体是RL中的挑战性问题。很难去训练出一个能够泛化到具有不同语义类别、不同几何形状和不同功能物体上的策略。 Visual Afforda…

粒子群算法对pi控制器进行参数优化,随时优化pi参数以控制直流无刷电机转速。

粒子群算法对pi控制器进行参数优化&#xff0c;随时优化pi参数以取得设定直流无刷电机转速。 PSO优化PID&#xff0c;用于BLDC速度控制 仿真平台为&#xff1a;MATLAB 采用的是Simulinkm程序相配合 仿真结果以及程序示例&#xff1a;

Armv8状态寄存器

Processor state AArch64没有与ARMv7当前程序状态寄存器直接对应的寄存器(CPSR)。在AArch64中&#xff0c;传统CPSR的组件以字段的形式提供可独立访问。这些统称为处理器状态(PSTATE)。 在AArch64中&#xff0c;通过执行ERET指令从异常中返回&#xff0c;这会导致要拷贝到PSTAT…

IEEE802.11v协议介绍

IEEE802.11v协议简介 协议全称:无线网络管理(Wireless Network Management) 批准日期:2011年2月 协议状态:并入802.11-2012 协议别名:BSS过渡管理 主要功能 支持AP和STA间交换:关于RF环境和拓扑状态的信息,以协助STA进行漫游决策支持STA之间交换:关于RF环境状态的信…

嵌入式单片机学习思路感想分享

今天看到了一个提问,原话如下: 曾经干了8年单片机工程师,对工程师从入门,到入行,再到普通,再到高级,整个路径还算清晰,比如什么阶段,会碰到什么瓶颈,怎么突破,我都经历过。 这个同学,有个典型的问题,就是学得太多且杂了,估计稍微复杂点的项目,做不出来。 现在…

superset连接Apache Spark SQL(hive)过程中的各种报错解决

superset连接数据库官方文档&#xff1a;Installing Database Drivers | Superset 我们用的是Apache Spark SQL&#xff0c;所以首先需要安装下pyhive #命令既下载了pyhive也下载了它所依赖的其他安装包 pip install pyhive#多个命令也可下载 pip install sasl pip install th…