ClickHouse简介

  • ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS),使用 C++
    语言编写,主要用于在线分析处理查询(OLAP),能够使用 SQL 查询实时生成分析数据报
    告。

ClickHouse的特点

列式存储

  • 首先先来看看,行式存储是怎么样的,下面那张表
    在这里插入图片描述

  • 当我们是行式存储的时候,数据是一行一行的存储的,如下图
    在这里插入图片描述

  • 但是当我们是列式存储的时候就不一样了,是一列一列存储的,如下图
    在这里插入图片描述

  • 而clickhouse就是列式储存,但是行式存储跟列式存储有什么区别吗,或者说双方的优缺点是什么?

  • 行式存储的优缺点:

    • 优点:
      • 数据都被保存到一起
      • 添加,修改,删除操作相对比较容易
    • 缺点:
      • 当你只是想要查询一条记录中的几列的时候,会把一条记录所有列的数据搜索出来,导致搜索太慢
    • 应用场景:
      • 适合随机的增删改查操作
      • 需要在行中选取所有属性的查询操作
      • 需要频繁插入或更新的操作,其操作与索引和行的大小更为相关
  • 列式存储的优缺点:

    • 优点:
      • 查询时,只有涉及到的列会被读取,所以查询速度会相对较快
      • 投影很高效
      • 任何列都可以作为索引
    • 缺点:
      • 选择完成时,被选择的列要重新组装
      • 添加,修改,删除操作相对比较麻烦
    • 应用场景:
      • 查询需要大量行但是少数几个列
      • 用于存储海量数据,并且修改操作不多的场景

DBMS的功能

  • 几乎覆盖了标准SQL的大部分语法,包括DDL和DML,以及配套的各种函数,用户管理及权限管理,数据的备份与恢复

多样化引擎

  • ClickHouse和MySQL类似,把表级的存储引擎插件化,根据表的不同需求可以设定不同的存储引擎。目前包括合并树,日志,接口和其他四大类20多种引擎。

高吞吐写入能力

  • ClickHouse 采用类 LSM Tree的结构,数据写入后定期在后台 Compaction。通过类 LSM tree的结构,ClickHouse 在数据导入时全部是顺序 append 写,写入后数据段不可更改,在后台compaction 时也是多个段 merge sort 后顺序写回磁盘。顺序写的特性,充分利用了磁盘的吞吐能力,即便在 HDD 上也有着优异的写入性能。
  • 官方公开 benchmark 测试显示能够达到 50MB-200MB/s 的写入吞吐能力,按照每行100Byte 估算,大约相当于 50W-200W 条/s 的写入速度。

数据分区与线程级并行

  • ClickHouse 将数据划分为多个 partition,每个 partition 再进一步划分为多个 index granularity(索引粒度),然后通过多个 CPU核心分别处理其中的一部分来实现并行数据处理。在这种设计下,单条 Query 就能利用整机所有 CPU。极致的并行处理能力,极大的降低了查询延时。
  • 所以,ClickHouse 即使对于大量数据的查询也能够化整为零平行处理。但是有一个弊端就是对于单条查询使用多 cpu,就不利于同时并发多条查询。所以对于高 qps 的查询业务,ClickHouse 并不是强项。

性能对比

  • ClickHouse 像很多 OLAP 数据库一样,单表查询速度由于关联查询,而且 ClickHouse 的两者差距更为明显。

ClickHouse的安装

前期环境准备

  1. 打开虚拟机,使用ulimit -a 命令查看相关配置,open files是指用户打开文件最大的数量,max user processes 指的是 一个用户最大的连接数,调整这个的目的是因为clickhouse很吃CPU,所以为了有更好的体验所以需要调整
    在这里插入图片描述
  2. 使用命令 sudo vim /etc/security/limits.conf 进入相关配置,并且加入下面那些配置
    在这里插入图片描述
  3. 使用命令 sudo vim /etc/security/limits.d/20-nproc.conf 进入相关配置,并且加入下面那些配置
    在这里插入图片描述
  4. 安装依赖,yum install -y libtoolyum install -y *unixODBC*
  5. centos上取消selinux,修改 /etc/selinux/config 中的 selinux = disabled
    在这里插入图片描述

单机安装

  • 官网:https://clickhouse.tech/
  • 下载地址:http://repo.red-soft.biz/repos/clickhouse/stable/el7/
  • 在/opt下创建clickhouse目录
    在这里插入图片描述
  • 将对应的资料放在clickhouse下
    在这里插入图片描述
  • 在目录下使用命令rpm -ivh *.rpm安装,
    在这里插入图片描述
  • 使用命令rpm -qa|grep clickhouse 查看一下
    在这里插入图片描述
  • 由于rpm安装不是在专门的目录下,所以文件都在etc下,然后我们修改配置文件,就需要跑到/etc/clickhouse-server下面
    在这里插入图片描述
  • 打开 config.xml文件进行配置,搜索listen,并且把 <listen_host>::</listen_host> 的注释打开,这样的话才能让 ClickHouse 被除本机以外的服务器访问
    在这里插入图片描述
  • 在这个文件中,有 ClickHouse 的一些默认路径配置,比较重要的
    • 数据文件路径: /var/lib/clickhouse/
    • 日志文件路径:/var/log/clickhouse-server/clickhouse-server.log
  • 然后就可以启动clickhouse , 使用命令clickhouse start 启动clickhouse,使用命令 clickhouse status 可以查看clickhouse 的状态
    在这里插入图片描述
  • 使用client链接server,clickhouse-client -m
    在这里插入图片描述
  • 至此安装完成

数据类型

  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 型:有符号的浮点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。
    • 使用场景: 一般金额字段、汇率、利率等字段为了保证小数点精度,都使用 Decimal 进行存储
    • Decimal32(s),相当于 Decimal(9-s,s),有效位数为 1~9
    • Decimal64(s),相当于 Decimal(18-s,s),有效位数为 1~18
    • Decimal128(s),相当于 Decimal(38-s,s),有效位数为 1~38
  5. 字符串
    • String:字符串可以任意长度的。它可以包含任意的字节集,包含空字节。
    • FixedString(N):固定长度 N 的字符串,N 必须是严格的正自然数。当服务端读取长度小于 N 的字符串时候,通过在字符串末尾添加空字节来达到 N 字节长度。 当服务端读取长度大于 N 的字符串时候,将返回错误消息。与 String 相比,极少会使用 FixedString,因为使用起来不是很方便。
    • 使用场景:名称、文字描述、字符型编码。 固定长度的可以保存一些定长的内容,比如一些编码,性别等但是考虑到一定的变化风险,带来收益不够明显,所以定长字符串使用意义有限。
  6. 枚举类型
    • 包括 Enum8 和 Enum16 类型。Enum 保存 ‘string’= integer 的对应关系
      • Enum8 用 ‘String’= Int8 对描述。
      • Enum16 用 ‘String’= Int16 对描述。
  7. 时间类型
    • Date 接受年-月-日的字符串比如 ‘2019-12-16’
    • Datetime 接受年-月-日 时:分:秒的字符串比如 ‘2019-12-16 20:50:10’
    • Datetime64 接受年-月-日 时:分:秒.亚秒的字符串比如‘2019-12-16 20:50:10.66’

表引擎

  • 表引擎是Clickhouse 的一大特色。可以说,表引擎决定了如何存储表的数据。包括:
    • 数据的存储方式和位置,写到哪里以及从哪里读取数据。
    • 支持哪些查询以及如何支持。
    • 并发数据访问。
    • 索引的使用(如果存在)。
    • 是否可以执行多线程请求。
    • 数据复制参数。
  • 表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎使用的相关参数。

TinyLog

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

Memory

  • 内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失。读写操作不会相互阻塞,不支持索引。简单查询下有非常非常高的性能表现。
  • 一般用到它的地方不多,除了用来测试,就是在需要非常高的性能,同时数据量又不太大的场景

MergeTree

  • clickhouse中最强大的表引擎当属MergeTree引擎及该系列中的其他引擎,支持索引和分区,地位可以相当于innodb之于Mysql。而且基于MergeTree,还衍生除了很多小弟,也是非常有特色的引擎。
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);
  • partition by 表示的是分区,上述sql所用的就是说根据创建时间进行分区
  • primary key 代表的是主键,特点如下:
    • 并不会唯一
    • 索引
  • order by 代表的是根据那两个字段进行排序
  • 尝试插入数据
insert into t_order_mt values
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
(102,'sku_002',2000.00,'2020-06-01 11:00:00'),
(102,'sku_004',2500.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 13:00:00'),
(102,'sku_002',12000.00,'2020-06-01 13:00:00'),
(102,'sku_002',600.00,'2020-06-02 12:00:00');

在这里插入图片描述

partition by 分区(可选)
  • 作用:降低扫描的范围,优化查询速度
  • 分区目录:MergeTree是以列文件 + 索引文件 + 表定义文件组成的,但是如果设定了分区那么这些文件就会保存到不同的分区目录中。
  • 并行:分区后,面对涉及跨分区的查询统计,Clickhouse会以分区为单位并行处理。
  • 数据写入与分区合并:任何一个批次的数据写入都会产生一个临时分区,不会纳入任何一个已有的分区。写入后的某个时刻,clickhouse会自动执行合并操作,把临时分区的数据,合并到已有分区中。
  • 分区文件目录:
    • bin文件:数据文件
    • mrk文件:标记文件
      • 标记文件在idx索引文件和bin数据文件之间起了桥梁作用
      • 以mrk2结尾的文件,表示该表启用了自适应索引间隔
    • primary.idx文件:主键索引文件,用于加快查询效率
    • minmax_create_time.idx:分区键的最大最小值
    • checksums.txt:校验文件,用于校验各个文件的正确性。存放各个文件的size以及hash值
  • 分区id生成规则:
    • 未定义分区键:没有定义partition by, 默认生成一个目录名为all的数据分区,所有数据均存放在all目录下。
    • 整型分区键:分区键为整型,那么直接用该整型值的字符串形式做为分区ID
    • 日期类分区键:分区键为日期类型,或者可以转化为日期类型。
    • 其他类型分区键:String,Float类型等,通过128位的Hash算法取其Hash值作为分区ID
  • MinBlockNum:最小分区块编号,自增类型,从1开始向上递增。
  • MaxBlockNum:最大分区块编号,新创建的分区MinBlockNum等于MaxBlockNum的编号
primary key 主键(可选)
  • clickhouse中的主键只提供了数据的一级索引,但是却不是唯一约束。这就意味着是可以存在相同primary key的数据的。
  • 主键的设定主要依据是查询语句中的where条件
  • 根据条件通过对主键进行某种形式的二分查找,能够定位到对应的索引粒度(index granularity),避免了全表扫描
  • index granularity:索引粒度,指在稀疏索引中两个相邻索引对应数据的间隔。Clickhouse中的MergeTree默认是8192.官方不建议修改这个值,除非该列存在大量重复值。
  • 稀疏索引:是可以用很少的索引数据,定位更多的数据,代价就是只能定位到索引粒度的第一行,然后再进行进行一点扫描。
    在这里插入图片描述
order by(必选)
  • order by 设定了分区内的数据按照哪些字段顺序进行有序保存。
  • order by 是 MergeTree 中唯一一个必填项,甚至比 primary key 还重要,因为当用户不设置主键的情况,很多处理会依照 order by 的字段进行处理(比如后面会讲的去重和汇总)。
  • 要求:主键必须是 order by 字段的前缀字段。比如 order by 字段是 (id,sku_id) 那么主键必须是 id 或者(id,sku_id)
数据TTL
  • TTL 即 Time To Live,MergeTree 提供了可以管理数据表或者列的生命周期的功能。
    在这里插入图片描述
    在这里插入图片描述

ReplacingMergeTree

  • ReplacingMergeTree 是 MergeTree 的一个变种,它存储特性完全继承 MergeTree,只是多了一个去重的功能。 尽管 MergeTree 可以设置主键,但是 primary key 其实没有唯一约束的功能。如果你想处理掉重复的数据,可以借助这个 ReplacingMergeTree。
  • 去重的时机:数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以你无法预测先作出计划。有一些数据可能仍未被处理。
  • 去重的范围:如果表经过了分区,去重只会在分区内部进行去重,不能执行跨分区的去重。所以ReplacingMergeTree只适用于在后台清楚重复的数据以节省空间,但是它不保证没有重复的数据出现
  • 结论:
    • 实际上是使用 order by 字段作为唯一键
    • 去重不能跨分区
    • 只有同一批插入(新版本)或合并分区时才会进行去重
    • 认定重复的数据保留,版本字段值最大的
    • 如果版本字段相同则按插入顺序保留最后一笔

SummingMergeTree

  • 对于不查询明细,只关心以维度进行汇总聚合结果的场景。如果只使用普通的MergeTree的话,无论是存储空间的开销,还是查询时临时聚合的开销都比较大。ClickHouse 为了这种场景,提供了一种能够“预聚合”的引擎 SummingMergeTree
  • 案例演示:
    在这里插入图片描述
    在这里插入图片描述
  • 结论:
    • 以 SummingMergeTree()中指定的列作为汇总数据列
    • 可以填写多列必须数字列,如果不填,以所有非维度列且为数字列的字段为汇总数据列
    • 以 order by 的列为准,作为维度列
    • 其他的列按插入顺序保留第一行
    • 不在一个分区的数据不会被聚合
    • 只有在同一批次插入(新版本)或分片合并时才会进行聚合

SQL操作

Insert

  • 在表内插入一条数据:insert into [table_name] values(…),(….)
  • 在表内插入一个表的数据:insert into [table_name] select a,b,c from [table_name_2]

Update 和 Delete

  • ClickHouse 提供了 Delete 和 Update 的能力,这类操作被称为 Mutation 查询,它可以看做 Alter 的一种。
  • 虽然可以实现修改和删除,但是和一般的 OLTP 数据库不一样,Mutation 语句是一种很“重”的操作,而且不支持事务。
  • “重”的原因主要是每次修改或者删除都会导致放弃目标数据的原有分区,重建新分区。所以尽量做批量的变更,不要进行频繁小数据的操作。
  • 删除操作:alter table t_order_smt delete where sku_id =‘sku_001’;
  • 修改操作:alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id =102;
  • 由于操作比较“重”,所以 Mutation 语句分两步执行,
    • 同步执行的部分其实只是进行新增数据新增分区和并把旧分区打上逻辑上的失效标记。
    • 直到触发分区合并的时候,才会删除旧数据释放磁盘空间,一般不会开放这样的功能给用户,由管理员完成。

查询操作

  • ClickHouse 基本上与标准 SQL 差别不大:
    • 支持子查询
    • 支持 CTE(Common Table Expression 公用表表达式 with 子句)
    • 支持各种 JOIN,但是 JOIN 操作无法使用缓存,所以即使是两次相同的 JOIN 语句,ClickHouse 也会视为两条新 SQL
    • GROUP BY 操作增加了 with rollup\with cube\with total 用来计算小计和总计。
      • with rollup:从右至左去掉维度进行小计
        在这里插入图片描述

      • with cube : 从右至左去掉维度进行小计,再从左至右去掉维度进行小计
        在这里插入图片描述

      • with totals: 只计算合计
        在这里插入图片描述

alter 操作

  • 新增字段:alter table tableName add column newcolname String after col1;
  • 修改字段类型:alter table tableName modify column newcolname String;
  • 删除字段:alter table tableName drop column newcolname;

副本

分片集群

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐