英文地址
https://medium.com/@f1yegor/clickhouse-primary-keys-2cf2a45d7324
译文
问题
- How many columns primary key could have? And what is layout of data on storage drive? Is there any theoretical/practical limits?
- Could columns with missing data at some rows be part of primary key?
存储格式
列式存储
相对于行存储,在读取的时候可以减少IO开销,但是在写入的时候会相对比较麻烦点。
MergeTree 存储结构
Columns.txt记录的每一列的信息。
每一列都有一个bin文件和mrk文件,其中bin文件是实际的数据存储
primary.idx存储主键信息,结构与mrk一样,类似于一个稀疏索引。
在MergeTree进行查询的时候,最关键的在于定位Block。根据主键进行查询的时候性能会比较好,但是在进行非主键的查询的时候,由于是按照列存储的关系,会进行一次全扫描。
源码分析
Columns
含义:表示内存中的列,使用IColumn接口,这个接口提供用于实现各种关系操作符的辅助方法,但是几乎所有的操作都是不可变的,不会改变原始列,但是可以创建一个新的修改列。
不同的IColumn实现福别不同的内存布局。内存布局退出时一个连续的数组,但是也有特殊的,比如String,Array等就是使用两个向量来组成的。
Field
Field是一个enum
enum Which
{
Null = 0,
UInt64 = 1,
Int64 = 2,
Float64 = 3,
UInt128 = 4,
Int128 = 5,
/// Non-POD types.
String = 16,
Array = 17,
Tuple = 18,
Decimal32 = 19,
Decimal64 = 20,
Decimal128 = 21,
AggregateFunctionState = 22,
};
IDataType
负责序列化与反序列化,读写二进制或者文本形式的列或者单个值构成的块。IDataType直接与表中的数据类型相对应
IDataType
与IColumn
之间的关联并不大,不同类型的IDatatType
可以使用相同的IColumn
来表示。
IDataType
仅仅存储源数据
Block
Block
是表示内存中表的子集(Chunk)的子集,由{IColumn,IDataType,列名}
三元组构成。
在查询执行期间,数据是按照Block
进行处理的,
Block Streams
Block Streams
用于处理数据,Block Streams
从某个地方读取数据,并进行数据转换,或者将数据写入到某个地方。
IBlockInputStream
具有read
方法,而IBlockOutputStream
具有write
方法。
IO
使用ReadBuffer
和WriteBuffer
两个抽象类,来替代iostream
。这两个类实现用于处理文件、文件描述符、socket,也可以用于进行压缩
Table
table由IStorage
接口表示,这个接口实现对应不同的表引擎,实现也不一样。比如StorageMergeTree,StorageMemory
IStorage
最主要的方法就是write read alter rename drop
等方法