什么是ClickHouse?
ClickHouse 是面向OLAP 的分布式列式DBMS.
在“正常”的面向行的DBMS中,数据按顺序进行存储:
5123456789123456789 1 Eurobasket - Greece - Bosnia and Herzegovina -
example.com 1 2011-09-01 01:03:02 6274717 1294101174 11409
612345678912345678 0 33 6
http://www.example.com/basketball/team/123/match/456789.htmlhttp://www.example.com/basketball/team/123/match/987654.html
0 1366 768 32 10 3183 0 0 13 0\0
1 1 0 0 2011142 -1 0 0
01321 613 660 2011-09-01 08:01:17 0 0 0 0 utf-8
1466 0 0 0 5678901234567890123 277789954 0
0 0 0 0
5234985259563631958 0 Consulting, Tax assessment, Accounting, Law
1 2011-09-01 01:03:02 6320881 2111222333 213
6458937489576391093 0 3 2 http://www.example.ru/ 0
800 600 16 10 2 153.1 0 0 10 63 1
1 0 0 2111678 000 0 588 368 240
2011-09-01 01:03:17 4 0 60310 0 windows-1251 1466 0
000 778899001 0 0 0 0 0
...
换句话说,与一行相关的所有值都被存储在一起。面向行的DBMS主要有MySQL,Postgres,MSSQL Server等等。
在面向列的DBMS中,数据存储如下:
WatchID:5385521489354350662 5385521490329509958 5385521489953706054
5385521490476781638 5385521490583269446 5385521490218868806
5385521491437850694 5385521491090174022 5385521490792669254
5385521490420695110 5385521491532181574 5385521491559694406
5385521491459625030 5385521492275175494 5385521492781318214
5385521492710027334 5385521492955615302 5385521493708759110
5385521494506434630 5385521493104611398
JavaEnable:1 0 1 0 0 0 1 0 1 1
1 1 1 1 0 1 0 0 1 1
Title:Yandex Announcements - Investor Relations - Yandex Yandex — Contact
us — Moscow Yandex — Mission Ru Yandex — History — History of
Yandex Yandex Financial Releases - Investor Relations - Yandex Yandex
—Locations Yandex Board of Directors - Corporate Governance- Yandex
Yandex — Technologies
GoodEvent:1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
EventTime:2016-05-18 05:19:20 2016-05-1808:10:20 2016-05-18 07:38:00
2016-05-1801:13:08 2016-05-18 00:04:06 2016-05-1804:21:30 2016-05-18
00:34:16 2016-05-1807:35:49 2016-05-18 11:41:59 2016-05-18 01:13:32...
这些示例仅显示数据排列的顺序。不同列的值分开存储,同一列的数据一起存储。例如,面向列的DBMS:Vertica,Paraccel(ActianMatrix)(AmazonRedshift),SybaseIQ,Exasol,Infobright,InfiniDB,MonetDB(VectorWise)(ActianVector),LucidDB,SAPHANA,GoogleDremel,GooglePowerDrill,Druid
,kdb +等。
存储数据的不同存储顺序更适合于不同的应用场景。数据访问场景指的是执行什么查询,多长时间查询,每种类型的查询读取多少数据 -
行,列和字节;写取和更新数据之间的关系;数据的大小以及它在本地的使用情况;是否使用交易处理,以及它们是如何隔离的;数据同步和逻辑完整性的要求;每类查询的延迟和吞吐量要求等等。
系统上的负载越高,场景化的系统定制就越重要,定制化就越具体。没有一个系统能够适用于截然不同的应用场景。如果一个系统可以适应多种场景,那么在高负载情况下,系统处理所有场景表现都会很差,或者仅其中一种场景表现良好。
对于OLAP(联机分析处理)方案,将会有如下几种应用场景:
- 绝大多数请求是以读为主。
- 数据以相当大的批次(>1000行)进行更新,而不是单行更新;或者根本不更新。
- 数据被添加到数据库,基本不怎么修改。
- 对于读取,大量的数据从数据库中抽取出来,但只有列的一个子集。
- 表是“宽的”,这意味着它们包含大量的列。
- 查询相对较少(通常每台服务器数百个查询或更少)。
- 对于简单的查询,允许大约50 ms的延迟。
- 列值相当小 - 数字和短字符串(例如,每个URL 60个字节)。
- 处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行)。
- 无事务处理。
- 数据一致性要求低- 每个查询有一个大表,其他所有的表都是小表。
- 查询结果显著小于源数据。也就是说,数据被过滤或聚合。结果可以放在单个服务器的内存中。
很容易看出,OLAP方案与其他常见方案(如OLTP或Key-Value访问)有很大不同。所以,如果你想获得不错的表现,尝试使用OLTP或Key-ValueDB来处理分析查询是没有意义的。例如,如果您尝试使用MongoDB或Elliptics进行分析,与OLAP数据库相比,您的性能会很差。
面向列的数据库更适合于OLAP方案(对于大多数查询,处理速度至少提高了100倍),原因如下:
1. 对于I/O
2. 对于分析查询,只需要读取少量的列。在面向列的数据库中,您只能读取所需的数据。例如,如果您需要100列中的5列,则I/O可能会减少20倍。
3. 由于数据是以数据包的形式读取的,因此压缩比较容易。列中的数据也更容易压缩。这进一步减少了I/O量。
4. 由于减少的I/O,更多的数据适合在系统缓存中。
例如,查询“统计每个广告平台的记录数量”需要读取一个“广告平台ID”列,其占用1个未压缩字节。如果大多数流量不是来自广告平台,那么您可以期望至少有10倍的压缩比。当使用快速压缩算法时,数据解压缩速度可以达到每秒至少几千兆字节的未压缩数据。换句话说,这个查询可以在一台服务器上以每秒大约几十亿行的速度处理。这个速度实际上是在实践中是容易实现的。
例如:
milovidov@hostname:~$clickhouse-client
ClickHouseclient version 0.0.52053.
Connectingto localhost:9000.
Connectedto ClickHouse server version 0.0.52053.
:)SELECT CounterID, count() FROM hits GROUP BY CounterID ORDER BY count()
DESCLIMIT20
SELECT
CounterID,
count()
FROMhits
GROUP BYCounterID
ORDER BYcount() DESC
LIMIT 20
┌─CounterID─┬──count()─┐
│ 114208│56057344│
│ 115080│51619590│
│ 3228│44658301│
│ 38230│42045932│
│ 145263│42042158│
│ 91244│38297270│
│ 154139│26647572│
│ 150748│24112755│
│ 242232│21302571│
│ 338158│13507087│
│ 62180│12229491│
│ 82264│12187441│
│ 232261│12148031│
│ 146272│11438516│
│ 168777│11403636│
│ 4120072│11227824│
│ 10938808│10519739│
│ 74088│ 9047015│
│ 115079│ 8837972│
│ 337234│ 8205961│
└───────────┴──────────┘
20 rows in set. Elapsed: 0.153 sec. Processed 1.00 billion rows, 4.00 GB (6.53
billion rows/s.,26.10 GB/s.)
1. 对于CPU
由于执行查询需要处理大量的行,因此它有助于为整个向量调度所有操作,而不是单独的行,或者实现查询引擎,这样就几乎没有调度成本。如果你不这样做,任何半象限的磁盘子系统(half-decent
disk subsystem),查询解释器不可避免地中断(阻塞)CPU。将数据存储在列中并在可能的情况下按列处理是有意义的。
有两种方法可以做到这一点:
1. 向量引擎(A vector
engine)。所有的操作都是为向量而写的,而不是单独的值。这意味着您不需要经常调用操作,调度成本可以忽略不计。操作代码包含一个优化的内部循环。
2. 代码生成(Code generation)。为查询生成的代码具有所有的间接调用。
这不是在“普通”数据库中完成的,因为运行简单查询时没有意义。但是,也有例外。例如,MemSQL在处理SQL查询时使用代码生成来减少延迟。(为了比较,分析DBMS需要优化吞吐量,而不是延迟。)
请注意,为了提高CPU效率,查询语言必须是声明式的(SQL或MDX),或者至少是一个向量(J,K)。查询应该只包含隐式循环,以便优化。
热门工具 换一换