Clickhouse学习文档

1. Clickhouse介绍

ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS),使用lz4压缩数据,压缩率高。
OLAP场景的关键特征:

  • 绝大多数是读请求
  • 数据以相当大的批次(> 1000行)更新,而不是单行更新;或者根本没有更新。
  • 已添加到数据库的数据不能修改。
  • 对于读取,从数据库中提取相当多的行,但只提取列的一小部分。
  • 宽表,即每个表包含着大量的列
  • 查询相对较少(通常每台服务器每秒查询数百次或更少)
  • 对于简单查询,允许延迟大约50毫秒
  • 列中的数据相对较小:数字和短字符串(例如,每个URL 60个字节)
  • 处理单个查询时需要高吞吐量(每台服务器每秒可达数十亿行)
  • 事务不是必须的
  • 对数据一致性要求低
  • 每个查询有一个大表。除了他以外,其他的都很小。
  • 查询结果明显小于源数据。换句话说,数据经过过滤或聚合,因此结果适合于单个服务器的RAM中。

在讲列式存储之前讲下行式存储,行式存储是处于同一行中的数据总是被物理的存储在一起。
常见的行式数据库系统有:MySQLPostgresMS SQL Server

Row #0 #1 #2 #N
WatchID 89354350662 90329509958 89953706054
JavaEnable 1 0 1
Title Investor Relations Contact us Mission
GoodEvent 1 1 1
EventTime 42508.22175925926 42508.34050925926 42508.31805555556

2. 数仓分层

定义:
ods是在数仓中存储业务系统源数据,所以从数据粒度、数据结构、数据关系等各个方面都与业务系统的数据源保持一致。
dim以维度作为建模驱动,基于每个维度的业务含义,通过添加维度属性、关联维度等定义计算逻辑,完成属性定义的过程并建立一致的数据分析维表。为了避免在维度模型中冗余关联维度的属性,基于雪花模型构建维度表。(类似于基础表)
dwd以业务过程作为建模驱动,基于每个具体的业务过程特点,构建最细粒度的明细事实表。可以结合企业的数据使用特点,将明细事实表的某些重要属性字段做适当冗余,也即宽表化处理。(类似于业务表)
dws以分析的主题对象作为建模驱动,基于上层的应用和产品的指标需求,构建公共粒度的汇总指标表。以宽表化手段物理化模型,构建命名规范、口径一致的统计指标,为上层提供公共指标,建立汇总宽表、明细事实表。
ads存放数据产品个性化的统计指标数据,根据CDM层与ODS层加工生成。

3. Clickhouse引擎

clickhouse表引擎非常丰富,有合并树引擎(MergeTree),日志引擎,集成的表引擎,在新建表时需要指定表引擎。

create table table_name(columns)
engine=engine_name
order by 主键
partition by 分区
SETTINGS index_granularity = n --间隔n行建立稀疏索引

3.1 MySQL引擎

MySQL引擎用于将远程的MySQL服务器中的表映射到ClickHouse中,并允许对表进行INSERTSELECT查询,以方便在ClickHouse与MySQL之间进行数据交换。
创建数据库语句:

CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster]
ENGINE = MySQL('host:port', ['database' | database], 'user', 'password')

clickhouse对应MySQL的数据类型有以下几种:
Clickhouse学习文档_第1张图片
除了MySQL引擎之外,还支持Hive、MongoDB、SQLite、PostgreSQL、HDFS等等几种数据库引擎。

3.2 合并树家族引擎

3.2.1 MergeTree

Clickhouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(*MergeTree)中的其他引擎。
MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。
主要特点:

  • 存储的数据按主键排序,能够创建一个小型的稀疏索引来加快数据检索。
  • 如果指定了分区键的话,可以使用分区。在相同数据集和相同结果集的情况下 ClickHouse 中某些带分区的操作会比普通操作更快。查询中指定了分区键时 ClickHouse 会自动截取分区数据。这也有效增加了查询性能。(在项目中通常使用时间作为分区键,toYYYYMMDD(dc_update_time),用数据的更新时间去分区)
  • 支持数据副本。
  • 支持数据采样。

3.2.2 ReplacingMergeTree

继承MergeTree引擎,和MergeTree的不同之处在于它会删除排序键值相同的重复项。
数据的去重只会在数据合并期间进行,合并会在后台一个不确定的时间进行。有一些数据可能仍未被处理。尽管可以调用 OPTIMIZE 语句发起计划外的合并,但 OPTIMIZE 语句会引发对数据的大量读写,不建议使用。
因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。
项目中的表目前大部分以这种引擎为主,由于更新数据是往数据库插入,故需使用argMax函数去重,才能使用这部分数据,argMax函数使用见第4节。

3.2.3 CollapsingMergeTree

该引擎继承于MergeTree,并在数据块合并算法中添加了折叠行的逻辑。
CollapsingMergeTree异步的删除(折叠)这些除了特定列 Sign1-1 的值以外,其余所有字段的值都相等的成对的行。没有成对的行会被保留。
因此,该引擎可以显著的降低存储量并提高 SELECT 查询效率。
CollapsingMergeTree 参数

  • sign — 类型列的名称: 1 是«状态»行,-1 是«取消»行。列数据类型 — Int8。

3.2.4 SummingMergeTree

该引擎继承自 MergeTree。区别在于,当合并 SummingMergeTree 表的数据片段时,ClickHouse 会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值。如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度。
我们推荐将该引擎和 MergeTree 一起使用。例如,在准备做报告的时候,将完整的数据存储在 MergeTree 表中,并且使用 SummingMergeTree 来存储聚合数据。
SummingMergeTree 的参数

  • columns - 包含了将要被汇总的列的列名的元组。可选参数。 所选的列必须是数值类型,并且不可位于主键中。
如果没有指定 `columns`,ClickHouse 会把所有不在主键中的数值类型的列都进行汇总。

4. clickhouse函数

4.1 时间函数

  1. toDate
    可以将字符串、时间戳转换为时间。
-- 显示当前日期  2022-09-17
select toDate(now())
-- 将字符串转换为日期(注意:这里不能用0.000这种带小数点的秒,不然无法转换)
select toDate('2022-01-01 00:00:00')
-- 将秒级时间戳转换为日期(注意:这里是秒级,不是毫秒级)
select toDate(1663301647)
  1. toDateTime64
    与toDate函数相似,但这个函数需多加一个精度的值,精度为10^-n秒。
-- 时间戳
select toDateTime64(1663301647,3)
-- 字符串
select toDateTime64('2022-01-01 00:00:00.000',3)
  1. toYYYYMMDD
    格式化时间,需传一个日期类型(不能为字符串),有toYYYYMM、toYYYYMMDD、toYYYYMMDDhhmmss几个格式化函数。
-- 202209
select toYYYYMM(today())
-- 20220917
select toYYYYMMDD(today())
-- 20220917164457
select toYYYYMMDDhhmmss(now()); 
  1. now
    当前时间有now和now64两个函数,now的类型是DateTime,now64的类型是DateTime64(3)。

4.2 json函数

visitParamHas(参数,名称)可以判断参数是否存在这个键。
json函数的功能主要是将字符串识别成json,并提取第一个识别到的键的值。

  • visitParamExtractString(参数,名称):这个函数会提取字符串并进行转义
  • visitParamExtractRaw(参数,名称):提取值(包括字符串、数字等等)不进行转义
  • visitParamExtractBool(参数,名称):提取boolean
  • visitParamExtractInt(参数,名称)
  • visitParamExtractUInt(参数,名称)
  • visitParamExtractFloat(参数,名称)

4.3 去重函数

使用聚合函数argMax,argMin可以通过时间取到首次的数据和最后一次更新的数据。

select argMax(id, t.dc_update_time)                    as id,
              receipt_code,
              argMax(order_code, t.dc_update_time)            as order_code,
              argMax(seq_order_no, t.dc_update_time)          as seq_order_no,
              argMax(source_code, t.dc_update_time)           as source_code,
              argMax(supplier_code, t.dc_update_time)         as supplier_code,
              argMax(supplier_name, t.dc_update_time)         as supplier_name,
              argMax(service_provider_code, t.dc_update_time) as service_provider_code,
              argMax(service_provider_name, t.dc_update_time) as service_provider_name,
              argMax(certificate, t.dc_update_time)           as certificate,
              argMax(amount, t.dc_update_time)                as amount,
              argMax(use_amount, t.dc_update_time)            as use_amount,
              argMax(state, t.dc_update_time)                 as state,
              argMax(is_deleted, t.dc_update_time)            as is_deleted,
              argMax(creator_id, t.dc_update_time)            as creator_id,
              argMax(creator_name, t.dc_update_time)          as creator_name,
              argMax(created_time, t.dc_update_time)          as created_time,
              argMax(reviser_id, t.dc_update_time)            as reviser_id,
              argMax(reviser_name, t.dc_update_time)          as reviser_name,
              argMax(revised_time, t.dc_update_time)          as revised_time,
              argMax(dc_update_time, t.dc_update_time)        as dc_update_time,
              argMax(dc_etl_time, t.dc_update_time)           as dc_etl_time
       from dwd_acc_deposit_receipt_cp_di t
       group by receipt_code

这个sql主要是对receipt_code先进行分组,然后组内对每个数据获取时间的最大值,再取这条数据,这样去重,可以实现每个receipt_code都可以拿到最新的数据。argMin也是相同的用法,可以取到首次的数据。
这里去重也可以使用final关键字(不推荐),根据ReplacingMergeTree引擎的特性,每次合并都会去重数据,final是合并数据达到去重效果,但是会增加IO消耗,不推荐使用。

5. 物化视图

物化视图是包括一个查询结果的数据库对象,它是远程数据的的本地副本,或者用来生成基于数据表求和的汇总表。物化视图存储基于远程表的数据,简单的来理解就是它在普通视图的基础上加上了视图中select后所存储的数据。
物化视图这些规则已经全部写好并且条件所过滤后的数据已经存储在了本地表中,所以它比原数据查询快了很多。
它是一个流式数据的使用场景,是累加式的技术,所以要用历史数据做去重、去核这样的分析,在物化视图里面是不太好用的。在某些场景的使用也是有限的。而且如果一张表加了好多物化视图,在写这张表的时候,就会消耗很多机器的资源,比如数据带宽占满、存储一下子增加了很多。

CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]table_name [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT

POPULATE取决于原始表的数据是否导入视图中,若不添加POPULATE关键字则不导入,但官方不推荐这种加POPULATE 的做法,因为我们在同步数据的时候原始表的数据可能存在被插入的情况,这样做会造成数据的丢失。

6. 海豚调度

  1. 写好clickhouse的ods、dwd等等这些采集脚本之后就可以把脚本上传到海豚调度上面。
  2. 这里新建了一个新的文件夹上传了一个文件之后需删除重新上传(有bug),把脚本放进对应的文件夹里。
  3. 定义好命令和资源位置,海豚调度是分布式调度,执行任务时需将这些资源进行统一打包,然后发送到worker上执行。
  4. 保存时还需设置好全局变量。
  5. 然后上线工作流,运行。

采集调度任务通过cron表达式完成调度,在上线之后可以按定时按钮操作调度执行。
在项目中海豚调度ods分为三个部分:初始化、补偿、采集,dwd聚合ods(left join)。

  • ods初始化:初始化ods数据,在数据迁移部分及取MySQL数据即可。
  • ods补偿:丢失数据之后要对数据进行补偿,与初始化同一个脚本,只是初始化的更新时间是数据的创建时间,补偿任务的更新时间是当前时间。
  • ods采集:需通过binlog采集,flinkCDC将binlog数据采集到一张表binlog_bak.source_mysql_binlog后,对这张表进行数据来源的判断,分为不同来源的几张表:binlog_bak.source_change_log_xw、binlog_bak.source_change_log_xz等等,通过source_change_log_xw表获取玄武数据库的binlog变更,再拿到attrStr字段的json,通过visitParamExtractRaw拿到值后去重,插入到表中,即完成了采集。

你可能感兴趣的:(SQL,clickhouse,学习,数据库)