什么是 ClickHouse?
ClickHouse® 是一款面向联机分析处理 (OLAP) 的高性能、面向列的 SQL 数据库管理系统 (DBMS)。它既可以作为 开源软件,也可以作为 云产品。
什么是 OLAP?
OLAP 场景需要对大型数据集进行实时响应,以处理具有以下特征的复杂分析查询
- 数据集可以是海量的——数十亿或数万亿行
- 数据组织在包含许多列的表中
- 仅选择少数几列来回答任何特定查询
- 结果必须在毫秒或秒内返回
面向列的数据库与面向行的数据库
在面向行的 DBMS 中,数据按行存储,与一行相关的所有值都物理地存储在一起。
在面向列的 DBMS 中,数据按列存储,来自同一列的值存储在一起。
为什么面向列的数据库在 OLAP 场景中效果更好?
面向列的数据库更适合 OLAP 场景:在处理大多数查询时,它们的速度至少快 100 倍。原因将在下面详细说明,但事实更容易用视觉方式展示
面向行的 DBMS
面向列的 DBMS
看到区别了吗?
本文的其余部分解释了为什么面向列的数据库适合这些场景,以及为什么 ClickHouse 尤其在 性能方面优于该类别中的其他数据库。
为什么 ClickHouse 如此快?
ClickHouse 利用所有可用的系统资源,将其发挥到极致,以尽可能快地处理每个分析查询。这是由于分析能力与实现最快 OLAP 数据库所需的低级细节的独特结合。
以下文章可以帮助您更深入地了解此主题
实时处理分析查询
在面向行的 DBMS 中,数据按以下顺序存储
行 | WatchID | JavaEnable | 标题 | GoodEvent | EventTime |
---|---|---|---|---|---|
#0 | 89354350662 | 1 | 投资者关系 | 1 | 2016-05-18 05:19:20 |
#1 | 90329509958 | 0 | 联系我们 | 1 | 2016-05-18 08:10:20 |
#2 | 89953706054 | 1 | 使命 | 1 | 2016-05-18 07:38:00 |
#N | … | … | … | … | … |
换句话说,与一行相关的所有值都物理地存储在一起。
面向行的 DBMS 的示例包括 MySQL、Postgres 和 MS SQL Server。
在面向列的 DBMS 中,数据按以下方式存储
行 | #0 | #1 | #2 | #N |
---|---|---|---|---|
WatchID | 89354350662 | 90329509958 | 89953706054 | … |
JavaEnable | 1 | 0 | 1 | … |
标题 | 投资者关系 | 联系我们 | 使命 | … |
GoodEvent | 1 | 1 | 1 | … |
EventTime | 2016-05-18 05:19:20 | 2016-05-18 08:10:20 | 2016-05-18 07:38:00 | … |
这些示例仅显示数据排列的顺序。来自不同列的值分别存储,来自同一列的数据存储在一起。
面向列的 DBMS 的示例:Vertica、Paraccel(Actian Matrix 和 Amazon Redshift)、Sybase IQ、Exasol、Infobright、InfiniDB、MonetDB(VectorWise 和 Actian Vector)、LucidDB、SAP HANA、Google Dremel、Google PowerDrill、Druid 和 kdb+。
不同的数据存储顺序更适合不同的场景。数据访问场景是指执行哪些查询,频率如何,以及比例如何;每个查询类型读取多少数据——行、列和字节;读取数据与更新数据之间的关系;数据的处理规模以及在多大程度上本地使用数据;是否使用事务,以及事务的隔离程度如何;对数据复制和逻辑完整性的要求;对每种查询类型的延迟和吞吐量的要求,等等。
系统负载越高,将系统设置定制为匹配使用场景的要求就越重要,这种定制也越细致。没有哪个系统能同时适合显著不同的场景。如果一个系统可以适应各种场景,那么在高负载下,该系统将对所有场景的处理效果都一样差,或者只对一两个可能的场景处理效果好。
OLAP 场景的关键属性
- 表是“宽”的,这意味着它们包含大量列。
- 数据集很大,查询在处理单个查询时需要高吞吐量(每秒每台服务器高达数十亿行)。
- 列值相当小:数字和短字符串(例如,每个 URL 60 字节)。
- 查询提取大量行,但只提取一小部分列。
- 对于简单查询,允许大约 50 毫秒的延迟。
- 每个查询只有一个大表;所有表都很小,除了一个。
- 查询结果明显小于源数据。换句话说,数据经过过滤或聚合,因此结果适合单个服务器的 RAM。
- 查询相对较少(通常每台服务器每秒数百个查询或更少)。
- 插入操作以相当大的批次(>1000 行)进行,而不是以单行进行。
- 不需要事务。
不难看出,OLAP 场景与其他流行的场景(如 OLTP 或键值访问)有很大不同。因此,如果想要获得良好的性能,就不要尝试使用 OLTP 或键值数据库来处理分析查询。例如,如果您尝试使用 MongoDB 或 Redis 进行分析,那么与 OLAP 数据库相比,您将获得非常糟糕的性能。
输入/输出
- 对于分析查询,只需要读取少量表列。在面向列的数据库中,您可以只读取所需的数据。例如,如果您需要 100 列中的 5 列,那么预计 I/O 量将减少 20 倍。
- 由于数据以数据包的形式读取,因此更容易压缩。列中的数据也更容易压缩。这进一步减少了 I/O 量。
- 由于 I/O 量减少,更多数据适合系统缓存。
例如,查询“统计每个广告平台的记录数量”需要读取一个“广告平台 ID”列,该列未压缩时占用 1 字节。如果大部分流量不是来自广告平台,那么预计该列至少可以压缩 10 倍。当使用快速压缩算法时,数据解压缩的速度至少可以达到每秒解压缩数千兆字节未压缩数据。换句话说,此查询可以在单台服务器上以每秒约数十亿行的速度进行处理。事实上,这种速度在实践中可以实现。
CPU
由于执行查询需要处理大量行,因此有助于对整个向量而不是单独的行分派所有操作,或者以一种几乎没有分派成本的方式实现查询引擎。如果不这样做,在任何半像样的磁盘子系统上,查询解释器都不可避免地会阻塞 CPU。有意义的是,将数据存储在列中,并在可能的情况下按列对其进行处理。
有两种方法可以做到这一点
向量引擎。所有操作都是针对向量编写的,而不是针对单独的值。这意味着您不需要频繁调用操作,分派成本可以忽略不计。操作代码包含一个优化的内部循环。
代码生成。为查询生成的代码包含所有间接调用。
在面向行的数据库中不会这样做,因为在运行简单查询时没有意义。然而,也有一些例外。例如,MemSQL 使用代码生成来减少处理 SQL 查询时的延迟。(相比之下,分析型 DBMS 需要优化吞吐量,而不是延迟。)
需要注意的是,为了提高 CPU 效率,查询语言必须是声明式的(SQL 或 MDX),或者至少是向量式的(J,K)。查询应该只包含隐式循环,以允许优化。