ClickHouse是俄罗斯第—大搜索引擎Yandex开发的列式储存数据库,这个列式储存数据库的性能大幅超越了很多商业MPP数据库软件,所以花了一段时间实际应用了一下,其出众的速度征服了我,还是很有应用前景的。
接下来我将逐步更新这个系列的文章,内容包括ClickHouse单机安装部署、监听端口、客户端访问接口、可视化客户端、导入导出数据、MergeTree系列表引擎、其他表引擎、ClickHouse分布式集群、Oracle同步数据到Clickhouse以及一些爬坑经验,含金量很足,敬请关注。
《手摸手带你学ClickHouse》之安装部署
1、Clickhouse简介
1.1 简介
官网:https://clickhouse.tech/,ClickHouse是面向 OLAP 的分布式列式DBMS。
优点:
1、灵活的MPP架构,支持线性扩展,简单方便,高可靠性
2、多服务器分布式处理数据,完备的DBMS系统
3、底层数据列式存储,优化索引数据
4、快:比Vertica快5倍,比Hive快279倍,比MySQL快800倍,其可处理的数据级别已达到10亿级别
5、功能多:支持数据统计分析各种场景,支持类SQL查询,异地复制部署。
ClickHouse 正是以不依赖Hadoop 生态、支持海量数据存储,分布式运算,快速闪电的性能,几乎实时的数据分析,友好的SQL语法,出色的函数支持等特点在大数据分析领域越走越远。
缺点:
1、 不擅长多表join操作,建议使用一个大宽表
2、 不支持事务
3、尽量做1000行以上的批量写入,避免逐行或小批量insert、update和delete。
1.2 应用场景
1、绝大多数请求都是用于读访问的,要求实时返回结果
2、数据需要以大批次(大于1000行)进行更新,而不是单行更新;或者根本没有更新操作。
3、数据只是添加到数据库,没有必要修改
4、读取数据时,会从数据库中提取出大量的行,但只用到一小部分列
5、表很“宽”,即表中包含大量的列
6、查询频率相对较低(通常每台服务器每秒查询数百次或更少)
7、对于简单查询,允许大约50毫秒的延迟
8、列的值是比较小的数值和短字符串(例如,每个URL只有60个字节)
9、在处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行)
10、不需要事务
11、数据一致性要求较低
12、每次查询中只会查询一个大表。除了一个大表,其余都是小表
13、查询结果显著小于数据源。即数据有过滤或聚合。返回结果不超过单个服务器内存木小。
1.3 架构
ClickHouse常用大数据处理架构
2、 ClickHouse单机安装部署
2.1 环境准备
用于安装的RPM包可以从下面两个仓库中任选一个下载:
https://repo.yandex.ru/clickhouse/rpm/stable/x86_64/
https://packagecloud.io/altinity/clickhouse
2.1.1 安装文件清单
需要下载以下4个安装包文件,版本根据自己需要,但是每个RPM文件的版本号要一致。
clickhouse-client-{version}.noarch. rpm
clickhouse-common-static-{version}.x86_64.rpm
clickhouse-common-static-dbg-{version}.x86_64.rpm
clickhouse-server-{version }.noarch. rpm
注:这里有几个版本需要注意,20.6.3开始支持explain,所以建议大于此版本号。同时在20.8开始支持实时同步mysql,根据需要自行选择,我这里使用21.3.9.83-2版本。
2.1.2 检查环境依赖
验证当前服务器CPU是否支持SSE 4.2指令集,因为向量化执行需要用到。
grep -q sse4_2 /proc/cpuinfo && echo “SSE 4.2 supported” || echo “SSE 4.2 not supported”
2.1.3 设置FQDN
在/etc/hosts中添加你服务器的FQDN,例如
hostnamectl --static set-hostname test1.com
配置hosts文件,加入内容,添加后如下:
cat /etc/hosts
注:配置集群时把每个节点都加入,以保证局域网内能互相访问。
2.1.4 安装命令
命令1(系统依赖包安装的比较完整时用此命令):
rpm -ivh *.rpm
命令2(使用此命令缺的依赖包会自动安装):
yum install *.rpm
安装完成后如下所示
2.2 目录结构
2.2.1 核心目录
(1)/etc/clickhouse-server
服务端的配置文件目录,包括全局配置config.xml和用户配置users.xml等。
(2)/var/lib/clickhouse
默认的数据存储目录
(3)/var/log/clickhouse-server
默认的日志保存目录
2.2.2 配置文件
(1)/etc/security/limits.d/clickhouse.conf
文件句柄数量的配置,默认如下:
该配置也可以通过config.xml的max_open_files修改。
(2)/etc/cron.d/clickhouse-server
cron定时任务配置,用于恢复因异常原因中断的ClickHouse服务进程。
2.2.3 可执行文件
/usr/bin目录下
(1)clickhouse:主程序的可执行文件。
(2)clickhouse-client:一个指向ClickHouse可执行文件的软链接,供客户端连接使用。
(3)clickhouse-server:一个指向ClickHouse可执行文件的软链接,供服务端启动使用。
(4)clickhouse-compressor:内置提供的压缩工具,可用于数据的正压反解。
2.3 启动服务
首先修改数据保存目录,以免空间不够。
cd /etc/clickhouse-server
vi config.xml
修改内容如下:
<path>/chbase/data/</path>
<tmp_path>/chbase/data/tmp/</tmp_path>
<user_files_path>/chbase/data/user_files/</user_files_path>
修改目录后,将目录Owner设置为clickhouse用户。
chown clickhouse:clickhouse /chbase/data/ -R
启动服务:
service clickhouse-server start
# 查看服务状态
service clickhouse-server status
# 服务停止
service clickhouse-server stop
# 服务重启
service clickhouse-server restart
注:如果提示如下Init script is already running,则使用如下命令启动:
systemctl start clickhouse-server.service
如果你是新版本,clickhouse还为我们提供了简单的命令
clickhouse start
clickhouse stop
clickhouse status
启动后查看监听的默认端口号9000
netstat -nltp|grep 9000
如上所示,则clickhouse已正常启动。
2.4 卸载
查看
rpm -qa | grep clickhouse
卸载命令:
rpm -e -rpm包名
2.5 设置账号密码
PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
这样可以得到两行数据,第一行是密码明文,第二行是密码密文
vim /etc/clickhouse-server/users.xml
找到 users --> default --> 标签下的password修改成password_sha256_hex,并把密文填进去
<password_sha256_hex>密码密文</password_sha256_hex>
添加密码后,命令行启动的方式为
clickhouse-client -h ip地址 -d default -m -u default --password 密码明文
上一篇文章《手摸手带你学ClickHouse》之安装部署,详细介绍了ClickHouse单机的安装部署,本文主要内容为ClickHouse监听端口、访问接口、设置允许其他ip访问以及可视化的客户端。
《手摸手带你学ClickHouse》之访问接口
1、Clickhouse的监听端口
clickhouse 的端口如下所示
这里先重点介绍 9000 以及 8123 端口。
1.1 9000端口
9000就是服务的默认监听端口号,在使用 clickhouse-client 连接时就是使用这个。
1.2 8123端口
8123则是JDBC网络远程连接时使用,后续使用java时就用此端口。
这些端口对应在配置文件 /etc/clickhouse-server/config.xml 中,如下
1.3 开放防火墙
防火墙开放8123和9000端口
firewall-cmd --add-port=8123/tcp --permanent --zone=public
firewall-cmd --reload
firewall-cmd --add-port=9000/tcp --permanent --zone=public
firewall-cmd --reload
2、客户端的访问接口
启动成功后,就可以启用客户端(clickhouse-client)进行连接,有两种命令执行方式,交互式执行和非交互式执行。
2.1 交互式执行
交互式执行就是直接运行 clickhouse-client 进行登录,和MySQL客户端类似,可以使用show databases、show tables等命令,如下
clickhouse-server client
或者
clickhouse-client -m
-m 可以执行一个多行语句
交互式执行的SQL会被记录到 ~/.clickhouse-client-history 文件中,如下
cat ~/.clickhouse-client-history
2.2 非交互式执行
非交互式执行主要用于批处理场景,例如数据导入导出等。在执行脚本命令时需要加上 --query 参数指定要执行的SQL语句。例如
clickhouse-client --query="select * from tb_test" > /chbase/db_test.tsv
3、允许其他ip访问
默认被允许访问的只有127.0.0.1,这里要先修改为允许其他 ip 也能访问
vim /etc/clickhouse-server/config.xml
修改如下内容(取消注释即可),如下
<listen_host>::</listen_host>
然后重启服务即可。
4、可视化客户端
由于JDBC网络远程连接需要使用8123端口,先确认8123可以被监听
netstat -tunlp|grep 8123
可视化工具这里我选择DBeaver(https://dbeaver.io/download/),如下
《手摸手带你学ClickHouse》之导入导出数据
1、导入数据
测试数据如下
解压
xz -d hits_v1.tsv.xz
xz -d visits_v1.tsv.xz
解压后
创建数据库
创建表
CREATE TABLE tutorial.hits_v1
(
`WatchID` UInt64,
`JavaEnable` UInt8,
`Title` String,
`GoodEvent` Int16,
`EventTime` DateTime,
`EventDate` Date,
`CounterID` UInt32,
`ClientIP` UInt32,
`ClientIP6` FixedString(16),
`RegionID` UInt32,
`UserID` UInt64,
`CounterClass` Int8,
`OS` UInt8,
`UserAgent` UInt8,
`URL` String,
`Referer` String,
`URLDomain` String,
`RefererDomain` String,
`Refresh` UInt8,
`IsRobot` UInt8,
`RefererCategories` Array(UInt16),
`URLCategories` Array(UInt16),
`URLRegions` Array(UInt32),
`RefererRegions` Array(UInt32),
`ResolutionWidth` UInt16,
`ResolutionHeight` UInt16,
`ResolutionDepth` UInt8,
`FlashMajor` UInt8,
`FlashMinor` UInt8,
`FlashMinor2` String,
`NetMajor` UInt8,
`NetMinor` UInt8,
`UserAgentMajor` UInt16,
`UserAgentMinor` FixedString(2),
`CookieEnable` UInt8,
`JavascriptEnable` UInt8,
`IsMobile` UInt8,
`MobilePhone` UInt8,
`MobilePhoneModel` String,
`Params` String,
`IPNetworkID` UInt32,
`TraficSourceID` Int8,
`SearchEngineID` UInt16,
`SearchPhrase` String,
`AdvEngineID` UInt8,
`IsArtifical` UInt8,
`WindowClientWidth` UInt16,
`WindowClientHeight` UInt16,
`ClientTimeZone` Int16,
`ClientEventTime` DateTime,
`SilverlightVersion1` UInt8,
`SilverlightVersion2` UInt8,
`SilverlightVersion3` UInt32,
`SilverlightVersion4` UInt16,
`PageCharset` String,
`CodeVersion` UInt32,
`IsLink` UInt8,
`IsDownload` UInt8,
`IsNotBounce` UInt8,
`FUniqID` UInt64,
`HID` UInt32,
`IsOldCounter` UInt8,
`IsEvent` UInt8,
`IsParameter` UInt8,
`DontCountHits` UInt8,
`WithHash` UInt8,
`HitColor` FixedString(1),
`UTCEventTime` DateTime,
`Age` UInt8,
`Sex` UInt8,
`Income` UInt8,
`Interests` UInt16,
`Robotness` UInt8,
`GeneralInterests` Array(UInt16),
`RemoteIP` UInt32,
`RemoteIP6` FixedString(16),
`WindowName` Int32,
`OpenerName` Int32,
`HistoryLength` Int16,
`BrowserLanguage` FixedString(2),
`BrowserCountry` FixedString(2),
`SocialNetwork` String,
`SocialAction` String,
`HTTPError` UInt16,
`SendTiming` Int32,
`DNSTiming` Int32,
`ConnectTiming` Int32,
`ResponseStartTiming` Int32,
`ResponseEndTiming` Int32,
`FetchTiming` Int32,
`RedirectTiming` Int32,
`DOMInteractiveTiming` Int32,
`DOMContentLoadedTiming` Int32,
`DOMCompleteTiming` Int32,
`LoadEventStartTiming` Int32,
`LoadEventEndTiming` Int32,
`NSToDOMContentLoadedTiming` Int32,
`FirstPaintTiming` Int32,
`RedirectCount` Int8,
`SocialSourceNetworkID` UInt8,
`SocialSourcePage` String,
`ParamPrice` Int64,
`ParamOrderID` String,
`ParamCurrency` FixedString(3),
`ParamCurrencyID` UInt16,
`GoalsReached` Array(UInt32),
`OpenstatServiceName` String,
`OpenstatCampaignID` String,
`OpenstatAdID` String,
`OpenstatSourceID` String,
`UTMSource` String,
`UTMMedium` String,
`UTMCampaign` String,
`UTMContent` String,
`UTMTerm` String,
`FromTag` String,
`HasGCLID` UInt8,
`RefererHash` UInt64,
`URLHash` UInt64,
`CLID` UInt32,
`YCLID` UInt64,
`ShareService` String,
`ShareURL` String,
`ShareTitle` String,
`ParsedParams` Nested(
Key1 String,
Key2 String,
Key3 String,
Key4 String,
Key5 String,
ValueDouble Float64),
`IslandID` FixedString(16),
`RequestNum` UInt32,
`RequestTry` UInt8
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID)
SETTINGS index_granularity = 8192;
CREATE TABLE tutorial.visits_v1
(
`CounterID` UInt32,
`StartDate` Date,
`Sign` Int8,
`IsNew` UInt8,
`VisitID` UInt64,
`UserID` UInt64,
`StartTime` DateTime,
`Duration` UInt32,
`UTCStartTime` DateTime,
`PageViews` Int32,
`Hits` Int32,
`IsBounce` UInt8,
`Referer` String,
`StartURL` String,
`RefererDomain` String,
`StartURLDomain` String,
`EndURL` String,
`LinkURL` String,
`IsDownload` UInt8,
`TraficSourceID` Int8,
`SearchEngineID` UInt16,
`SearchPhrase` String,
`AdvEngineID` UInt8,
`PlaceID` Int32,
`RefererCategories` Array(UInt16),
`URLCategories` Array(UInt16),
`URLRegions` Array(UInt32),
`RefererRegions` Array(UInt32),
`IsYandex` UInt8,
`GoalReachesDepth` Int32,
`GoalReachesURL` Int32,
`GoalReachesAny` Int32,
`SocialSourceNetworkID` UInt8,
`SocialSourcePage` String,
`MobilePhoneModel` String,
`ClientEventTime` DateTime,
`RegionID` UInt32,
`ClientIP` UInt32,
`ClientIP6` FixedString(16),
`RemoteIP` UInt32,
`RemoteIP6` FixedString(16),
`IPNetworkID` UInt32,
`SilverlightVersion3` UInt32,
`CodeVersion` UInt32,
`ResolutionWidth` UInt16,
`ResolutionHeight` UInt16,
`UserAgentMajor` UInt16,
`UserAgentMinor` UInt16,
`WindowClientWidth` UInt16,
`WindowClientHeight` UInt16,
`SilverlightVersion2` UInt8,
`SilverlightVersion4` UInt16,
`FlashVersion3` UInt16,
`FlashVersion4` UInt16,
`ClientTimeZone` Int16,
`OS` UInt8,
`UserAgent` UInt8,
`ResolutionDepth` UInt8,
`FlashMajor` UInt8,
`FlashMinor` UInt8,
`NetMajor` UInt8,
`NetMinor` UInt8,
`MobilePhone` UInt8,
`SilverlightVersion1` UInt8,
`Age` UInt8,
`Sex` UInt8,
`Income` UInt8,
`JavaEnable` UInt8,
`CookieEnable` UInt8,
`JavascriptEnable` UInt8,
`IsMobile` UInt8,
`BrowserLanguage` UInt16,
`BrowserCountry` UInt16,
`Interests` UInt16,
`Robotness` UInt8,
`GeneralInterests` Array(UInt16),
`Params` Array(String),
`Goals` Nested(
ID UInt32,
Serial UInt32,
EventTime DateTime,
Price Int64,
OrderID String,
CurrencyID UInt32),
`WatchIDs` Array(UInt64),
`ParamSumPrice` Int64,
`ParamCurrency` FixedString(3),
`ParamCurrencyID` UInt16,
`ClickLogID` UInt64,
`ClickEventID` Int32,
`ClickGoodEvent` Int32,
`ClickEventTime` DateTime,
`ClickPriorityID` Int32,
`ClickPhraseID` Int32,
`ClickPageID` Int32,
`ClickPlaceID` Int32,
`ClickTypeID` Int32,
`ClickResourceID` Int32,
`ClickCost` UInt32,
`ClickClientIP` UInt32,
`ClickDomainID` UInt32,
`ClickURL` String,
`ClickAttempt` UInt8,
`ClickOrderID` UInt32,
`ClickBannerID` UInt32,
`ClickMarketCategoryID` UInt32,
`ClickMarketPP` UInt32,
`ClickMarketCategoryName` String,
`ClickMarketPPName` String,
`ClickAWAPSCampaignName` String,
`ClickPageName` String,
`ClickTargetType` UInt16,
`ClickTargetPhraseID` UInt64,
`ClickContextType` UInt8,
`ClickSelectType` Int8,
`ClickOptions` String,
`ClickGroupBannerID` Int32,
`OpenstatServiceName` String,
`OpenstatCampaignID` String,
`OpenstatAdID` String,
`OpenstatSourceID` String,
`UTMSource` String,
`UTMMedium` String,
`UTMCampaign` String,
`UTMContent` String,
`UTMTerm` String,
`FromTag` String,
`HasGCLID` UInt8,
`FirstVisit` DateTime,
`PredLastVisit` Date,
`LastVisit` Date,
`TotalVisits` UInt32,
`TraficSource` Nested(
ID Int8,
SearchEngineID UInt16,
AdvEngineID UInt8,
PlaceID UInt16,
SocialSourceNetworkID UInt8,
Domain String,
SearchPhrase String,
SocialSourcePage String),
`Attendance` FixedString(16),
`CLID` UInt32,
`YCLID` UInt64,
`NormalizedRefererHash` UInt64,
`SearchPhraseHash` UInt64,
`RefererDomainHash` UInt64,
`NormalizedStartURLHash` UInt64,
`StartURLDomainHash` UInt64,
`NormalizedEndURLHash` UInt64,
`TopLevelDomain` UInt64,
`URLScheme` UInt64,
`OpenstatServiceNameHash` UInt64,
`OpenstatCampaignIDHash` UInt64,
`OpenstatAdIDHash` UInt64,
`OpenstatSourceIDHash` UInt64,
`UTMSourceHash` UInt64,
`UTMMediumHash` UInt64,
`UTMCampaignHash` UInt64,
`UTMContentHash` UInt64,
`UTMTermHash` UInt64,
`FromHash` UInt64,
`WebVisorEnabled` UInt8,
`WebVisorActivity` UInt32,
`ParsedParams` Nested(
Key1 String,
Key2 String,
Key3 String,
Key4 String,
Key5 String,
ValueDouble Float64),
`Market` Nested(
Type UInt8,
GoalID UInt32,
OrderID String,
OrderPrice Int64,
PP UInt32,
DirectPlaceID UInt32,
DirectOrderID UInt32,
DirectBannerID UInt32,
GoodID String,
GoodName String,
GoodQuantity Int32,
GoodPrice Int64),
`IslandID` FixedString(16)
)
ENGINE = CollapsingMergeTree(Sign)
PARTITION BY toYYYYMM(StartDate)
ORDER BY (CounterID, StartDate, intHash32(UserID), VisitID)
SAMPLE BY intHash32(UserID)
SETTINGS index_granularity = 8192;
导入数据
clickhouse-client --query "INSERT INTO tutorial.hits_v1 FORMAT TSV" --max_insert_block_size=100000 < hits_v1.tsv
7.3G数据,用时190秒
clickhouse-client --query "INSERT INTO tutorial.visits_v1 FORMAT TSV" --max_insert_block_size=100000 < visits_v1.tsv
2.5G数据,用时96秒
FORMAT TSV :导入的数据格式为TSV。
max_insert_block_size : 一次导入10万条记录。
2、查询数据效率
单表限制条件:
求和:
占用空间情况
表关联查询:
需要注意的是,关联查询时小表在后(大表 join 小表)
3、导出数据
clickhouse-client --query="select * from dbtest1.tb_merge_tree FORMAT CSV">/data/ClickHouse/tb_merge_tree.csv
《手摸手带你学ClickHouse》之MergeTree系列表引擎
前面的文章详细介绍了ClickHouse单机的安装部署、ClickHouse监听端口、访问接口、设置允许其他ip访问、可视化的客户端以及数据的导入导出。本文主要内容为ClickHouse数据存储功能的核心,也就是MergeTree系列的表引擎。
1、MergeTree系列表引擎
MergeTree系列的表引擎是ClickHouse数据存储功能的核心。它们提供了用于弹性和高性能数据检索的大多数功能:列存储,自定义分区,稀疏的主索引,辅助数据跳过索引等。基本MergeTree表引擎可以被认为是单节点ClickHouse实例的默认表引擎,因为它在各种用例中通用且实用。
除了基础表引擎MergeTree之外,常用的表引擎还有ReplacingMergeTree、SummingMergeTree、AggregatingMergeTree、CollapsingMergeTree和VersionedCollapsingMergeTree。
每一种合并树的变种,在继承了基础MergeTree的能力之后,又增加了独有的特性。其名称中的“合并”二字奠定了所有类型MergeTree的基因,它们的所有特殊逻辑,都是在触发合并的过程中被激活的。
主要特点:
- 存储按主键排序的数据。
- 如果指定了分区键则可以使用分区。
表引擎(即表的类型)决定了:
- 数据的存储方式和位置,写到哪里以及从哪里读取数据.
- 支持哪些查询以及如何支持。
- 并发数据访问。
- 索引的使用(如果存在)。
- 是否可以执行多线程请求。
- 数据复制参数。
后续内容将针对常用表引擎的使用进行详细讲解,下面我们先看基础表引擎MergeTree。
2、MergeTree表引擎
MergeTree表引擎是ClickHouse的基础表引擎,下面进行详细介绍。
2.1 创建表
create table tb_merge_tree(
uid UInt8,
name String,
birthday Date,
city String ,
gender String
)engine = MergeTree()
primary key uid
order by (uid ,birthday);
注:如果指定了主键,排序字段第一个字段必须是主键。如果没指定,则排序字段就是主键字段。
插入数据:
insert into tb_merge_tree values(1,'zhangsan',toDate(now()),'BJ','M'),
(2,'lisi',toDate(now()),'SH','M'),
(3,'wanger ','1996-01-05','BJ','M');
2.2 底层数据结构
接下来我们看下底层是怎么组织数据的,进入到数据存储目录
因为这个表没有建立分区,所以数据都在all这个里面
.bin的就是字段值,.mrk2是标记,标记数据的位置,checksums.txt是做数据校验的,count.txt记录当前数据的条数。
2.3 主键没有唯一性要求
在ClickHouse中主键可重复,没有唯一性要求,只是用来建立索引,如下,我们可以再插入一次相同数据
2.4 合并树
这里需要注意的是,如果再次插入数据,这里还会再产生一个all文件,因为是不同批次插入的数据,如下
可以看到数据也是分两块来存储
如果需要合并树,执行如下命令
optimize table tb_merge_tree;
或者
optimize table tb_merge_tree final;
加final的作用是如果有多个会同时一次性合并。
可以看到数据已合并到all_1_3_2中,过一段时间另外两个将会自动删除,如下
2.5 索引粒度
上面我们创建表的时候没有指定索引粒度,因为默认就是8192,查看一下建表语句
SETTINGS index_granularity = 8192
设置为8192就代表每隔8192行数据建一个索引,这样就大大节省了索引标记占用的空间,所以primary.idx内的索引数据常驻内存,取用速度就会很快。
2.6 分区
要使用分区需要在建表的时候指定partition by 字段名,如下
create table tb_merge_tree2(
uid UInt8,
name String,
birthday Date,
city String
)engine = MergeTree()
partition by birthday
primary key uid
order by (uid ,birthday);
这里指定了生日为分区,也就是日期相同的会在同一个分区,插入数据
insert into tb_merge_tree2 values(1,'zhangsan',toDate(now()),'BJ'),
(2,'lisi',toDate(now()),'KM'),
(3,'wanger ','1996-01-01','BJ'),
(3,'mazi ','1996-01-01','KM'),
(3,'mazi ','2000-11-11','KM');
可以看到,这里按日期建立了三个分区存储,在system的parts表中也可以查询到分区信息,如下
select table,name,partition from system.parts where table='tb_merge_tree2';
《手摸手带你学ClickHouse》之ReplacingMergeTree表引擎
前面的文章详细介绍了ClickHouse单机的安装部署、ClickHouse监听端口、访问接口、设置允许其他ip访问、可视化的客户端、数据的导入导出以及MergeTree表引擎。本文主要内容为ClickHouse的另外一个表引擎 ReplacingMergeTree。
1、基本使用
ReplacingMergeTree这个引擎区别于MergeTree的是增加了 分区内删除重复数据(按ORDER BY排序键为基准,而不是主键) 的功能,注意是分区内。但是去重只在数据合并时,而合并是后台自动在未知时间内进行,因此不保证没有重复数据的出现。
建表如下:
create table tb_replacing_mergetree(
uid UInt8,
name String,
birthday Date,
city String
)engine = ReplacingMergeTree()
partition by city
primary key uid
order by (uid ,name);
这里使用city字段来进行分区,主键为uid,排序字段为uid和name
插入数据
insert into tb_replacing_mergetree values(1,'zhangsan',toDate(now()),'BJ'),
(1,'lisi',toDate(now()),'KM'),
(1,'wanger ','1996-01-01','BJ'),
(1,'mazi ','1996-01-01','KM'),
(1,'mazi ','2000-11-11','KM');
接下来进行合并操作
optimize table tb_replacing_mergetree final;
合并后数据如下:
可以看到KM这个分区里uid和name重复的数据已经被合并。
2、删除数据版本控制
由于被删掉的数据默认按插入顺序来,保留的是最新插入的一条,这样就会有一个问题,可能老数据在新数据后插入,合并时就会删除那条新数据。
要解决这个问题,只需要在声明引擎时指定某个字段,就会默认保留该字段最大的那条数据。
例如:
create table tb_replacing_mergetree2(
uid UInt8,
name String,
age UInt8,
city String,
version UInt8
)engine = ReplacingMergeTree(version)
partition by city
primary key uid
order by (uid ,age);
insert into tb_replacing_mergetree2 values(1,'newname',25,'BJ',3),
(1,'wanger',26,'BJ',2),
(1,'mazi',26,'KM',2),
(1,'mazi',26,'KM',1),
(1,'oldname',25,'BJ',1);
合并后
optimize table tb_replacing_mergetree2 final;
可以看到,分区内指定的version字段最大的值被保留。
作者:樊同学