ClickHouse是什么?
ClickHouse® 是一款面向列的高性能 SQL 数据库管理系统(DBMS),用于在线分析处理(OLAP)。它可作为开源软件和云服务提供。
什么是OLAP?
OLAP 场景需要在庞大数据集上进行实时响应,用于复杂的分析查询,具有以下特点:
- 数据集可能非常庞大 - 亿万或万亿行
- 数据组织成包含许多列的表
- 每个特定查询只选择少数列
- 结果必须在毫秒或秒内返回
列式与行式数据库
在行式DBMS中,数据按行存储,与行相关的所有值物理上相邻存储。
在列式DBMS中,数据按列存储,相同列的值存储在一起。
为什么列式数据库在OLAP场景中更适用
列式数据库更适合OLAP场景:它们在处理大多数查询时至少快100倍。下面详细解释了原因,但事实更容易通过图示来展示:
行式DBMS
列式DBMS
看到区别了吗?
本文的其余部分解释了为什么列式数据库适用于这些场景,以及为什么ClickHouse特别优于其他同类产品。
为什么ClickHouse如此快?
ClickHouse充分利用所有可用的系统资源,以尽可能快的速度处理每个分析查询。这得益于分析能力和对实现最快OLAP数据库所需的低级细节的独特结合。
深入了解此主题的有用文章包括:
在实时处理分析查询
在行式DBMS中,数据按以下顺序存储:
Row | 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 | … | … | … | … | … |
换句话说,与行相关的所有值物理上相邻存储。
行式DBMS的例子包括MySQL、Postgres和MS SQL Server。
在列式DBMS中,数据存储如下:
Row: | #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 | … |
这些例子只显示了数据排列的顺序。不同列的值是分开存储的,相同列的数据是一起存储的。
列式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或键值DB来处理分析查询是没有意义的。例如,如果尝试使用MongoDB或Redis进行分析,与OLAP数据库相比,性能会非常差。
输入/输出
- 对于分析查询,只需要读取少量表列。在列式数据库中,您可以只读取所需的数据。例如,如果您需要100列中的5列,您可以期望I/O减少20倍。
- 由于数据是以数据包的形式读取的,因此更容易压缩。列中的数据也更容易压缩。这进一步减少了I/O量。
- 由于I/O减少,更多数据适合系统缓存。
CPU
由于执行查询需要处理大量行,因此有助于将所有操作分派给整个向量,而不是单独的行,或者实现查询引擎,以便几乎没有分派成本。如果不这样做,那么在任何半好的磁盘子系统中,查询解释器都会不可避免地使CPU停滞。在可能的情况下,存储数据并按列处理数据是有意义的。
有两种方法可以做到这一点:
- 向量引擎。所有操作都是针对向量而不是单独的值编写的。这意味着您不需要经常调用操作,分派成本可以忽略不计。操作代码包含优化的内部循环。
- 代码生成。为查询生成的代码中包含所有间接调用。
这在行式数据库中没有做,因为在运行简单查询时没有意义。但是,也有例外。例如,MemSQL使用代码生成来减少处理SQL查询时的延迟。(作为比较,分析DBMS需要优化吞吐量,而不是延迟。)
请注意,为了提高CPU效率,查询语言必须是声明性的(SQL或MDX),或者至少是向量(J、K)。查询应该只包含隐式循环,以便进行优化。