没有合适的资源?快使用搜索试试~ 我知道了~
首页ClickHouse 内部架构介绍.pdf
ClickHouse 内部架构介绍.pdf
需积分: 49 1.9k 浏览量
更新于2023-03-16
评论
收藏 189KB PDF 举报
Clickhouse是一个用于联机分析处理(OLAP)的列式数据库管理系统(columnar DBMS)。 传统数据库在数据大小比较小,索引大小适合内存,数据缓存命中率足够高的情形下能正常提供服务。但残酷的是,这种理想情形最终会随着业务的增长走到尽头,查询会变得越来越慢。你可能通过增加更多的内存,订购更快的磁盘等等来解决问题(纵向扩展),但这只是拖延解决本质问题。如果你的需求是解决怎样快速查询出结果,那么ClickHouse也许可以解决你的问题。
资源详情
资源评论
资源推荐

ClickHouse 内部架构介绍
ClickHouse 内部架构介绍内部架构介绍
http://www.clickhouse.com.cn/topic/5a3df7b02141c2917483557c
ClickHouse是一个完全面向列式的分布式数据库。数据通过列存储,在查询过程中,数据通过数组来处理(向量或者列Chunk)。当进行
查询时,操作被转发到数组上,而不是在特定的值上。因此被称为”向量化查询执行”,相对于实际的数据处理成本,向量化处理具有更低
的转发成本。
这个设计思路并不是新的思路理念。历史可以追溯到APL编程语言时代:A+, J, K, and Q。数组编程广泛用于科学数据处理领域。而在
关系型数据库中:也应用了向量化系统。
在加速查询处理上,有两种的方法:向量化查询执行和运行时代码生成。为每种查询类型都进行代码生成,去除所有的间接和动态转发处
理。这些方法并不比其他方法好,当多个操作一起执行时,运行时代码生成会更好,可以充分累用CPU执行单元和Pipeline管道。
向量化查询执行实用性并不那么高,因为它涉及到临时向量,必须写到缓存中,并读取回来。如果临时数据并不适合L2缓存,它可能
是一个问题。但是向量化查询执行更容易利用CPU的SIMD能力。一个研究论文显示将两个方法结合到一起效果会更好。ClickHouse主要使
用向量化查询执行和有限的运行时代码生成支持(仅GROUP BY内部循环第一阶段被编译)。
列
为了表示内存中的列(列的 chunks),IColumn将被使用。这个接口提供了一些辅助方法来实现不同的关系操作符。几乎所有的操作符
都是非更改的:他们不能更改原有的列,但是创建一个新的更新的列。例如,IColumn::filter方法接受一个过滤器字节掩码,同时创建一个
新的过滤列。它被用在WHERE和HAVING的关系操作符上。额外的示例:IColumn::permute方法支持ORDER BY,IColumn::cut方法支持
LIMIT等。
不同的IColumn实现(ColumnUInt8,ColumnString等)负责列的内存布局。内存布局通常是一个连续的数组。对于列的整型来说,它是一
个连续的数组,如std::vector。对于String和Array列,这个是2个vectors:一个是所有的数组元素,连续放置,另一个是偏移量(offsets),位于每个数
组的起始端。也有ColumnConst用于在内存中存储一个值,但是它看起来像一个列。
数据域
然而, 它也可能工作在单独的值上面。为了表示一个单独的值。数据域使用.Fieldis 这是一个UInt64,Int64,Float64,StringandArray可区分的
集合。IColumn 有operator[]方法来获得n-th值作为一个数据域,insert[] 方法追加一个数据域到一个列的末尾。这些方法不是特别高效,因
为他们需要处理临时的数据域对象,它代表一个单独的值。这是一个最高效的方法,例如insertFrom, insertRangeFrom等。
对于一个表,一个特定的数据类型,数据域没有足够的信息。例如 ,UInt8,UInt16,UInt32, 和 UInt64都用 UInt64表示。
抽象渗漏法则
IColumn有方法用于通用的关系型数据转换,但是它并不能满足所有需求。例如,ColumnUInt64没有方法来计算2个列的加
和,ColumnString没有方法用于运行子字符串的搜索。一些进程是在IColumn之外实现的。
列中的不同函数能够以一个通用的方式来实现,使用IColumn方法来抽取数据域值,或者在特定的方法下使用数据的内部内存布局在特
定的IColumn上实现。为了完成这个,函数将被转换成一个特定的IColumn类型,直接在内部进行处理。例如,ColumnUInt64有一个getData
方法,将返回一个内存数组的引用,然后一个单独的进程读取或者直接填充这个数组。事实上,我们有一个抽象渗漏法则来允许不同进程
的专用化。
数据类型
IDataType 负责序列化和反序列化: 读写这个列的值或者以二进制或文本的方式的值.IDataType 直接与表中的数据类型一致。例如,有
DataTypeUInt32,DataTypeDateTime,DataTypeString等。
IDataType和IColumnare 互相是松耦合的。不同的数据类型能够在内存中表示,通过相同的IColumn 实现.。例如,DataTypeUInt32和
DataTypeDateTime都是通过ColumnUInt32或者ColumnConstUInt32来表示。另外,相同的数据类型通过不同的IColumn实现来表示. 例
如,DataTypeUInt8 能够通过ColumnUInt8或者ColumnConstUInt8.来表示。
IDataType 仅存储元数据。例如,DataTypeUInt8 根本不保存任何数据 (除了 vptr) ,同时DataTypeFixedString 保存justN(确定的字符串
大小)。
IDataType 对于不同的数据格式都有协助方法。示例是有些方法可以序列化一个值, 序列化一个值到 JSON,序列化一个值到 XML 格式。
没有直接的数据格式一一对应。例如,不同的数据格式Pretty和TabSeparated 能够使用相同的serializeTextEscaped协助方法,在IDataType接
口中。
数据块
一个数据块是一个容器,代表了内存中一个表的子集。它也是三元组的集合:(IColumn,IDataType,columnname). 在查询执行过程中, 数
据通过数据块来处理. 如果你有一个数据块, 我们有数据(在IColumn对象中), 我们有这个数据的类型(在IDataType中) 告诉我们怎样处理此
列,同时我们有此列名称 (或者是原有列名, 或者是人工命名,得到计算的临时结果)。
在一个数据块中,当我们计算跨列某个函数时, 我们添加另外的带有结果的列到数据块中, 我们并不修改这个列,因为这些操作都是非变更
的。然后,不需要的列将从数据块中删除,但不是修改。这个对于消除子表达式是便捷的。
















安全验证
文档复制为VIP权益,开通VIP直接复制

评论0