clickhouse简介

ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的用于在线分析处理查询(OLAP :Online Analytical Processing)MPP架构列式存储数据库(DBMS:Database Management System),能够使用 SQL 查询实时生成分析数据报告。clickhouse可以做用户行为分析,流批一体,clickhouse没有走hadoop生态,采用 Local attached storage 作为存储。

clickhouse的特点

列式存储:列式存储更符合OLAP数据库的使用。

DBMS的功能:几乎覆盖了标准SQL的大部分语法,包括 DDL和 DML ,以及配套的各种函数,使用方便。

多样化引擎:clickhousemysql类似,把表级的存储引擎插件化,根据表的不同需求可以设定不同的库引擎和表引擎

高吞吐写入能力:ClickHouse采用类LSM Tree的结构,数据写入后定期在后台Compaction。通过类LSM tree的结构,ClickHouse在数据导入时全部是顺序append写,写入后数据段不可更改,在后台compaction时也是多个段merge sort后顺序写回磁盘。顺序写的特性,充分利用了磁盘的吞吐能力,即便在HDD上也有着优异的写入性能。

数据分区与线程级并行:ClickHouse将数据划分为多个partition,每个partition再进一步划分为多个index granularity,然后通过多个CPU核心分别处理其中的一部分来实现并行数据处理。在这种设计下,单条Query就能利用整机所有CPU。极致的并行处理能力,极大的降低了查询延时。

更适合单表查询:ClickHouse 像很多 OLAP 数据库一样,单表查询速度优于关联查询,而且 ClickHouse的两者差距更为明显。(clickhouse会将右表加载到内存)。

高可用:通过数据Replacing,提供了高可用嫩里。

单表查询效率极高

clickhouse查询为什么快?

  1. C++可以利用硬件优势。
  2. 摒弃了hadoop生态,底层存储使用算法极大的优化。
  3. 数据底层以列式存储,更适合数据分析,提高数据压缩的能力。
  4. 按照分区存储,而且每一列单独生成一个文件。
  5. 利用单节点的多核并行处理,极致的并行处理能力。
  6. 为数据建立索引一级、二级、稀疏索引。

数据类型

1.整型
固定长度的整型,包括有符号整型或无符号整型。

整型范围(-2n-1~2n-1-1):
Int8 - [-128 : 127]
Int16 - [-32768 : 32767]
Int32 - [-2147483648 : 2147483647]
Int64 - [-9223372036854775808 : 9223372036854775807]
无符号整型范围(0~2n-1):
UInt8 - [0 : 255]
UInt16 - [0 : 65535]
UInt32 - [0 : 4294967295]
UInt64 - [0 : 18446744073709551615]

2.浮点型
Float32 - float
Float64 – double
建议尽可能以整数形式存储数据。例如,将固定精度的数字转换为整数值,如时间用毫秒为单位表示,因为浮点型进行计算时可能引起四舍五入的误差。

适用场景:一般数据值比较小,不涉及大量的统计计算,精度要求不高的时候。比如保存商品的重量。

3.布尔型
没有单独的类型来存储布尔值。可以使用 UInt8 类型,取值限制为 0 或 1。

4.Decimal型
有符号的浮点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。

有三种声明:

Decimal32(s),相当于Decimal(9-s,s)
Decimal64(s),相当于Decimal(18-s,s)
Decimal128(s),相当于Decimal(38-s,s)
适用场景:一般金额字段,汇率,利率等字段为了保证小数点精度,都是用Decimal进行存储。

5.字符串
1)String
字符串可以任意长度的。它可以包含任意的字节集,包含空字节。

2)FixedString(N)
固定长度 N 的字符串,N 必须是严格的正自然数。当服务端读取长度小于 N 的字符串时候,通过在字符串末尾添加空字节来达到 N 字节长度。 当服务端读取长度大于 N 的字符串时候,将返回错误消息。

与String相比,极少会使用FixedString,因为使用起来不是很方便。

适用场景:名称,文字描述,字符型编码。固定长度的可以保存一些定长的内容,比如一些编码,性别等,但是考虑到一定的变化风险,带来收益不够明显,所以定长字符串使用意义有限。

6.枚举类型
包括 Enum8 和 Enum16 类型。Enum 保存'string'= integer 的对应关系。

Enum8 用 'String'= Int8 对描述。

Enum16 用'String'= Int16对描述。

用法演示:

--创建一个带有一个枚举 Enum8('hello' = 1, 'world' = 2) 类型的列:

CREATE TABLE t_enum
(
    x Enum8('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog

适用场景:对于一些状态,类型的字段算是一种空间优化,也算是一种数据约束。但是实际使用中往往因为一些数据内容的变化增加一定的维护成本,甚至是数据丢失的问题。所以谨慎使用。

7.时间类型
目前clickhouse 有三种时间类型

Date 接受 年-月-日 的字符串比如 ‘2019-12-16’

Datetime 接受 年-月-日 时:分:秒 的字符串比如 ‘2019-12-16 20:50:10’

Datetime64 接受 年-月-日 时:分:秒.亚秒 的字符串比如 ‘2019-12-16 20:50:10.66’
 

表引擎

TinyLog
以列文件的形式保存在磁盘上,不支持索引,没有并发控制。一般保存少量数据的小表,生产环境上作用有限。可以用于平时练习测试用。

Memory
内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失。读写操作不会相互阻塞,不支持索引。简单查询下有非常非常高的性能表现(超过10G/s)。

一般用到它的地方不多,除了用来测试,就是在需要非常高的性能,同时数据量又不太大(上限大概 1 亿行)的场景。

MergeTree
Clickhouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(MergeTree)中的其他引擎。地位可以相当于innodb之于Mysql。 而且基于MergeTree,还衍生出了很多小弟,也是非常有特色的引擎。

合并过程:详解clickhouse分区目录的合并过程_大大大大肉包的博客-CSDN博客

create table t_order_mt(
    id UInt32,
    sku_id String,
    total_amount Decimal(16,2),
    create_time  Datetime
 ) engine =MergeTree
 partition by toYYYYMMDD(create_time)
   primary key (id)
   order by (id,sku_id)
;

ReplacingMergeTree
ReplacingMergeTree是MergeTree的一个变种,它存储特性完全继承MergeTree,只是多了一个去重的功能。

尽管MergeTree可以设置主键,但是primary key其实没有唯一约束的功能。如果你想处理掉重复的数据,可以借助这个ReplacingMergeTree。

去重时机:数据的去重只会在合并的过程中和同一批插入的数据中出现。合并会在未知的时间在后台进行,所以你无法预先作出计划。有一些数据可能仍未被处理。

去重范围:如果表经过了分区,去重只会在分区内部进行去重,不能执行跨分区的去重。

所以ReplacingMergeTree能力有限, ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

手动去重

optimize table t_order_smt final;

ReplacingMergeTree()填入的参数为版本字段,重复数据保留版本字段值最大的。

如果不填版本字段,默认保留最后一条

  create table t_order_rmt(
    id UInt32,
    sku_id String,
    total_amount Decimal(16,2) ,
    create_time  Datetime 
 ) engine =ReplacingMergeTree(create_time)
 partition by toYYYYMMDD(create_time)
   primary key (id)
   order by (id, sku_id)

SummingMergeTree
对于不查询明细,只关心以维度进行汇总聚合结果的场景。如果只使用普通的MergeTree的话,无论是存储空间的开销,还是查询时临时聚合的开销都比较大。

Clickhouse 为了这种场景,提供了一种能够“预聚合”的引擎,SummingMergeTree。

以SummingMergeTree()中指定的列作为汇总数据列。可以填写多列必须数字列,如果不填,以所有非维度列且为数字列的字段为汇总数据列。以order by 的列为准,作为维度列。其他的列保留第一行。不在一个分区的数据不会被聚合。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐