跳至主要内容

什么是 ClickHouse?

ClickHouse® 是一款用于联机分析处理 (OLAP) 的高性能、面向列的 SQL 数据库管理系统 (DBMS)。它既可以作为 开源软件,也可以作为 云产品 提供。

什么是 OLAP?

OLAP 场景需要对大型数据集进行实时响应,以处理具有以下特征的复杂分析查询

  • 数据集可以很大 - 数十亿或数万亿行
  • 数据组织在包含许多列的表中
  • 仅选择少数列来回答任何特定查询
  • 结果必须在毫秒或秒内返回

面向列的数据库与面向行的数据库

在面向行的 DBMS 中,数据存储在行中,所有与行相关的值物理上存储在一起。

在面向列的 DBMS 中,数据存储在列中,来自相同列的值存储在一起。

为什么面向列的数据库在 OLAP 场景中效果更好

面向列的数据库更适合 OLAP 场景:它们在处理大多数查询时至少快 100 倍。原因将在下面详细解释,但事实更容易用视觉方式展示

面向行的 DBMS

Row-oriented

面向列的 DBMS

Column-oriented

看到区别了吗?

本文的其余部分将解释为什么面向列的数据库适合这些场景,以及为什么 ClickHouse 特别 优于该类别中的其他数据库。

为什么 ClickHouse 如此快?

ClickHouse 利用所有可用的系统资源,以其全部潜力来尽快处理每个分析查询。这是由于分析功能的独特组合以及对实现最快 OLAP 数据库所需的底层细节的关注所致。

以下文章有助于您更深入地了解此主题

实时处理分析查询

在面向行的 DBMS 中,数据以这种顺序存储

WatchIDJavaEnable标题GoodEventEventTime
#0893543506621投资者关系12016-05-18 05:19:20
#1903295099580联系我们12016-05-18 08:10:20
#2899537060541使命12016-05-18 07:38:00
#N

换句话说,所有与行相关的值都物理上存储在一起。

面向行的 DBMS 的示例包括 MySQL、Postgres 和 MS SQL Server。

在面向列的 DBMS 中,数据存储方式如下

#0#1#2#N
WatchID893543506629032950995889953706054
JavaEnable101
标题投资者关系联系我们使命
GoodEvent111
EventTime2016-05-18 05:19:202016-05-18 08:10:202016-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 数据库相比,您将获得非常差的性能。

输入/输出

  1. 对于分析查询,只需要读取表格的少数几列。在面向列的数据库中,您可以只读取所需的数据。例如,如果您需要 100 列中的 5 列,则可以预期 I/O 减少 20 倍。
  2. 由于数据以数据包形式读取,因此更容易压缩。列中的数据也更容易压缩。这进一步减少了 I/O 量。
  3. 由于 I/O 减少,更多数据适合系统缓存。

例如,查询“统计每个广告平台的记录数”需要读取一个“广告平台 ID”列,该列未压缩时占用 1 字节。如果大部分流量不是来自广告平台,您可以预期该列至少压缩 10 倍。当使用快速压缩算法时,数据解压缩的速度至少可以达到每秒解压缩数千兆字节未压缩数据。换句话说,此查询可以以每台服务器每秒约数十亿行的速度进行处理。这种速度实际上是在实践中实现的。

CPU

由于执行查询需要处理大量行,因此将所有操作调度到整个向量而不是单独的行,或者将查询引擎实现为几乎没有调度成本,将有所帮助。如果不这样做,使用任何半像样的磁盘子系统,查询解释器都会不可避免地阻塞 CPU。有必要将数据存储在列中,并尽可能通过列进行处理。

有两种方法可以做到这一点

  1. 向量引擎。所有操作都针对向量编写,而不是针对单独的值。这意味着您不需要经常调用操作,并且调度成本可以忽略不计。操作代码包含一个优化的内部循环。

  2. 代码生成。为查询生成的代码包含所有间接调用。

在面向行的数据库中没有这样做,因为在运行简单查询时这样做没有意义。但是,也有例外。例如,MemSQL 使用代码生成来减少处理 SQL 查询时的延迟。(相比之下,分析 DBMS 需要优化吞吐量,而不是延迟。)

请注意,为了提高 CPU 效率,查询语言必须是声明式的(SQL 或 MDX),或者至少是向量式的(J、K)。查询应该只包含隐式循环,以便进行优化。