简单介绍
clickHouse 是俄罗斯 yandex 公司开发的一款 OLAP 的列式数据库软件.
主要特点
- 数据的压缩(lz4, zstd, 不使用压缩算法)
- 数据存储介质(基于硬盘设计)
- 多核心并行处理(MPP 软件设计架构, 单个查询可以利用服务器上一切可以使用的资源)
- 支持分布式(分布式系统基于 zookpeer(paxos) 之上设计, 每个服务器实例只能作为分布式系统中的一个 shard)
- 支持 SQL(支持 SQL 对数据库的操作, 但是 sql 语句区分大小写)
- 支持向量引擎(利用 CPU 的 SIMD(单条指令操作多条数据) 指令来处理计算,)
- 高性能写入数据(以类似于 LSM 的方式追加数据)
- 支持数据索引(对主键进行稀疏索引的方式对主键进行排序, 加速数据的访问)
- 角色访问控制(基于 rbac 的访问控制)
- 支持数据的复制和校验数据的完整性
- 文档齐全
- 社区活跃
OLAP 的关键特征
- 绝大多数是读请求
- 数据以相当大的批次(> 1000 行)更新,而不是单行更新;或者根本没有更新。
- 已添加到数据库的数据不能修改。
- 对于读取,从数据库中提取相当多的行,但只提取列的一小部分。
- 宽表,即每个表包含着大量的列
- 查询相对较少(通常每台服务器每秒查询数百次或更少)
- 对于简单查询,允许延迟大约 50 毫秒
- 列中的数据相对较小:数字和短字符串(例如,每个 URL 60 个字节)
- 处理单个查询时需要高吞吐量(每台服务器每秒可达数十亿行)
- 事务不是必须的
- 对数据一致性要求低
- 每个查询有一个大表。除了他以外,其他的都很小。
- 查询结果明显小于源数据。换句话说,数据经过过滤或聚合,因此结果适合于单个服务器的 RAM 中
列式存储和行存储有什么不一样?
在常见的数据库软件比如: MySQL, mssql, oracel, pg 等都是以行存储的, 也就是说处于同一行的数据在物理存储中是保存在一起的, 比如:
| 数据行号 | WatchID | JavaEnable | Title | GoodEvent | EventTime |
|---|---|---|---|---|---|
| #0 | 89354350662 | 1 | Investor Relations | 1 | 2016-05-18 05:19:20 |
| #1 | 90329509958 | 0 | Contact us | 1 | 2016-05-18 08:10:20 |
| #2 | 89953706054 | 1 | Mission | 1 | 2016-05-18 07:38:00 |
| #N | … | … | … | … | … |
表现为同一张表的数据只会保存在同一个文件中.
比如 MySQL 数据库的文件:
CREATE TABLE `user_info` (
`id` int(11) DEFAULT NULL,
`updated_at` varchar(128) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
那么数据库的存储文件为:
db.opt
user_info.frm
user_info.ibd
其中, db.opt 文件是数据库的配置文件, user_info.frm 是 user_info 表的表结构文件, user_info.ibd 是 user_info 保存数据的文件.
在 clickhouse 存储的数据库系统中
CREATE TABLE xx_test.user_info
(
`id` String,
`updated_at` String
)
ENGINE = MergeTree
ORDER BY id
SETTINGS index_granularity = 8192;
| 行记录: | #0 | #1 | #2 | #N |
|---|---|---|---|---|
| WatchID: | 89354350662 | 90329509958 | 89953706054 | … |
| JavaEnable: | 1 | 0 | 1 | … |
| Title: | Investor Relations | Contact us | Mission | … |
| GoodEvent: | 1 | 1 | 1 | … |
| EventTime: | 2016-05-18 05:19:20 | 2016-05-18 08:10:20 | 2016-05-18 07:38:00 | … |
这些示例只显示了数据的排列顺序, 来自不同列的值被单独存储,来自同一列的数据被存储在一起
行和列存储有什么不一样: 在物理存储上看, 行存储是将所有的行记录都保存在同一个文件中; (使用老版本的)列存储是将相同的列记录保存在同一个文件中, 在新版本中, 同一个张表的数据已经保存在同一个文件中了.
由于物理存储的不一致, 按行存储的方式在读取数据中的数据时, 就必须先要进行数据的物理定位,然后将记录加载到内存中, 如果是选取行记录中的所有字段时, 那无疑效率是非常高的; 但是很多场景只是需要行记录中的某几个字段就足够了. 所以在这种场景下, 很多 cpu 和硬盘存储等都是对宝贵资源的浪费.
行和列存储数据操作效率对比
IO(磁盘/网络)
- 针对于分析类型的插叙你, 通常只是需要读取一张大表中的一小部分或者多张聚合表之后的一部分字段信息. 在列式存储数据库中, 我们只需要读取需要的数据. 比如只需要读取有一百个字段的大表中的 5 个字段, 这种情况下, 列式存储对行存储有巨大的优势
- 对于相同类型的数据结构, 数据的压缩是更具有优势的, 在压缩算法和元数据保存上更省空间和 cpu 计算, 这在存储空间和 I/O 上更加具有优势
- 由于 I/O 降低, 数据更容易使用 CPU 的 L3 缓存
cpu
// todo
不适合的场景
- 不支持事务
- 开源版本不支持 upset 数据操作
- 不支持删除操作
- 不适合高并发操作
- 由于使用散列的方式链接表, 并不太适用于 JOIN 的场景, 特别是表的数据特表大的情况下(在生产环境中, 不推荐, 不建议使用 JOIN 进行操作, 触发您能接受 clickhouse 的超长时间重启过程)
- 基于稀疏索引的数据组织方式, 单点查询能力不高
性能如何
性能对比图, 总结就是干翻了其他同类数据库
单个大查询的最大吞吐量
在单服务器上能够以 2~10GB/s 处理未压缩的数据.
对于简单的查询可达 30GB/s
在磁盘读取速度为 400MB/s 的情况下, 能够以 1~2 亿行每秒的速度处理压缩比率为 3 的列(每个列大小为 10 字节)
在分布式环境中, 可以线性拓展这个性能
数据的写入性能
建议每次写入不少于 1000 行的批量写入,或每秒不超过一个写入请求, 官方的压测数据: 写入速度大约为 50 到 200MB/s。如果您写入的数据每行为 1Kb,那么写入的速度为 50,000 到 200,000 行每秒。如果您的行更小,那么写入速度将更高。为了提高写入性能,您可以使用多个 INSERT 进行并行写入,这将带来线性的性能提升