栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

ClickHouse MergeTree表引擎和建表语句

ClickHouse MergeTree表引擎和建表语句

1. clickhouse使用场景

ClickHouse是由俄罗斯Yandex公司开发的、面向列的数据库管理系统(DBMS),主要面向OLAP场景,用于在线分析处理查询,可以使用SQL查询实时生成数据分析结果。列式存储的好处就是当我们对列进行聚合等操作时,效率会大大优于行式存储,而且由于每一列的类型都是相同的,所以对于数据存储更容易进行压缩,而且可以对不同类型的列选择更合适的压缩算法,节约资源。
clickhouse的设计也处处体现了俄罗斯的暴力美学,它不仅仅是一个数据库,还是一个数据库管理系统,后面我们在介绍基于SQL的用户管理、权限管理、资源管理,以及clickhouse本身在数据压缩、并行化计算等方面的特色,就会明白为什么会说clickhouse是一个数据库管理系统了。
clickhouse虽然在很多方面表现出了优异的性能,尤其是是在大数据量情况下的高效查询效率(ck和其他数据库的查询性能比较,可参考官方测试,但也并不意味着就适合所有数据库使用场景。ck的使用场景如下:

数据量较大。在ck官网的测试数据案例以及诸多大厂的实践中,数据量至少都是在百万条以上(大多数都是亿级)。如果使用传统数据库,如mysql、oracle、pg等数据库已经可以满足业务需求,那么就没必要强行引入ck,而且ck对用户暴露了很多使用配置,对开发人员的要求更高,运维成本更高。ck的请求绝大多数都是读请求。换句话说就是写请求很少,或者说不频繁(插入数据都是集中写)。例如,网站的行为日志分析,可以在凌晨把前一天的数据同步到ck中。当然,这并不是说ck的写入数据性能很弱,只是不适合细水长流的写操作。批量(> 1000行)更新,而不是单个行更新,或者根本就没有更新/修改操作。这也是ck和hive类似,但是又不同的地方。hive不支持alter、delete语句修改数据,ck支持此类操作,但是非常不建议针对极少数数据、频繁的做alter操作,尤其是在服务器比较忙碌的时候。最好是和hive一样,对分区做增删操作。读取很多行,但只提取了列的一小部分。换句话说就是,我的表很大、列很宽,但是每次查询的时候只使用其中部分字段,按需索取,所以如果不是必要,不建议在ck中使用 select * 的操作,尤其是宽表。宽表,即有很多列。换句话说就是数据在写入ck之前,已经打宽,避免在ck内做表关联操作,并不是说ck不支持join操作,只是相对查询而言性能会受影响(实际上ck的大表和小表join也并不比其他关系型数据库差)。查询相对较少(通常每台服务器每秒有数百个查询,甚至更少),这也就意味着ck不能直接作为业务系统的查询数据库,尤其是面向C端用户的业务系统,这主要是ck对服务器的CPU消耗极高导致的。所以ck多用在监控数据分析、日志分析、业务数据分析等场景,服务于平台和企业内部,例如,电商平台需要监控每三分钟刷新的热销商品销量排行。对于简单的查询,大约允许50毫秒的延迟。这是由于ck的稀疏索引导致的,使得ck对于通过键检索单行的点查询不那么有效。不同于hash索引,使用 where = * 条件可以直接定位到要查的数据,稀疏索引是通过对数据排序,然后建立等距采样点得到的,所以即使是 = 精准查询,也要多次比较得到。列中的数据相对较小,多为数字和短字符串。例如,URL、销量等。如果存文章、图片甚至视频就不合适了。在处理单个查询时需要高吞吐量(每台服务器每秒可处理数十亿行)。例如6中的热销商品监控。事务不是必须的。这是ck和mysql等数据库一个极大的不同点,ck不支持事务,也就说无法保证数据一致性。好消息是Yandex已经把事务支持排在远期目标了。对数据一致性要求低。一方面是因为ck不支持事务,还有一方面是因为ck的副本表在同步数据的时候不能保证数据一致性。例如,修改了副本A的数据,副本B的数据还没有完全同步好,此时如果分别查了副本A和副本B的数据,结果就不一致了。而且因为没有事务支持,如果是插入一万条记录,在写入三千条的时候,来了一个查询,查询结果是会把三千条涵盖进去的。所以ck在写入数据的时候为了保证数据一致性,有一种方案就是先建立一个临时表保存要插入的数据,然后把原表的历史数据也同步到临时表中,再rename原表为备份表、rename临时表为正式表,这样就可以保证数据一致性了,如果有问题只需要把备份表再rename为正式表就可以回滚了。每个查询都有一个大表。除了他以外,其他的表都很小。即尽量不要做大表和大表关联的操作。查询结果明显小于源数据。换句话说,数据被过滤或聚合,因此结果适合单个服务器的RAM。 2. ClickHouse表引擎

ClickHouse支持不同的表引擎,主要有MergeTree家族表引擎、Log家族表引擎、集成表引擎,以及一些特殊的表引擎。表引擎的主要作用是:

决定数据存储的方式和位置,向何处写入,从何处读取。如Log引擎数据是存在内存中。支持哪些查询以及如何支持。例如,有些功能只有MergeTree系列表引擎才支持。并发数据访问。索引的使用(如果存在)。是否可以执行多线程请求。数据复制参数。
其中MergeTree家族的表引擎是ClickHouse数据存储能力的核心,它们为弹性和高性能数据检索提供了大多数特性:列式存储、自定义分区、稀疏主索引、二级索引等。 3. MergeTree引擎建表语句

MergeTree表引擎是MergeTree家族表引擎最具代表性的表引擎,也是使用最为广泛的表引擎。MergeTree表引擎可以被认为是单节点ClickHouse实例的默认表引擎,因为它适用于各种各样的用例。建表语句如下:

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2,
    ...
    PROJECTION projection_name_1 (SELECT  [GROUP BY] [ORDER BY]),
    PROJECTION projection_name_2 (SELECT  [GROUP BY] [ORDER BY])
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr
    [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx' [, ...] ]
    [WHERe conditions]
    [GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ] ]
[SETTINGS name=value, ...]

ClickHouse的建表语句和hive类似,而且ck也是库名和用户名相互独立的。ck环境启动以后会有一个默认的default库,所以在创建表的时候,如果不指定库名,默认就是在default库下面创建。ON CLUSTER 表示在哪个集群上创建表,只有在分布式环境中才会使用,单节点表不需要考虑。和hive不同,ck在创建分布式表和副本表的时候需要在每个节点上单独执行建表语句(分布式表需要先创建local表),对于一个很大的集群,如果每次建表都要在所有节点上执行,无疑是很麻烦的,而且一般情况下为了做HA、负载均衡,并且方便使用,只会对应用端暴露一个负载虚拟IP,就无法在每个节点上执行建表语句,此时就可以在ck的配置文件中创建一个同步DDL语句的集群(需要依赖zookeeper),这样一旦执行DDL语句就可以通过zookeeper同步到所有节点上执行。ck的建表语句字段定义格式和其他关系型数据库一样,也是 字段名+字段类型 定义,也可以设置默认值,过期时间等。ck的数据类型可参考官网介绍。ENGINE = MergeTree() 表示定义表引擎是 MergeTree ,其他表引擎也是如此,只是名称和参数不同。在一些历史版本中,可能会见到带参数的MergeTree引擎建表语句,只是把后面的分区等建表参数作为了MergeTree()的参数而已,ck已经废弃了这种用法。PARTITION BY 定义分区字段,和hive一样,MergeTree表的不同分区数据也是存在不同的目录中,和hive每个分区数据是有不同的小文件组成不同,MergeTree的分区数据一般是有不同的列数据文件组成的,后面会详细介绍。PRIMARY KEY 定义主键字段,一般是通过ORDER BY字段定义,不单独定义,除非是和ORDER BY字段不同时才会单独定义主键字段,且必须是ORDER BY前面的字段,和其他数据库不同的是MergeTree的主键字段是可以重复的。ORDER BY 定义排序字段,也是MergeTree引擎最为重要的建表参数,通过建表语句也可以发现,其他定义字段都不是必须的,只有ORDER BY是必须的,当然如果实在不需要定义ORDER BY字段,可以使用 ORDER BY tuple() 语法建表。在使用insert … select 语句插入数据时,如果想保证数据存储顺序和插入顺序一致,除了不指定ORDER BY外,还需要设置 max_insert_threads = 1。如果没有定义主键字段,ORDER BY 字段就是主键,使用中多是不单独定义PRIMARY KEY,但是在 CollapsingMergeTree 和 SummingMergeTree 表引擎中,分开定义主键和排序键可能会更有意义。需要注意,即使单独定义主键和排序列,主键列也要位于排序列的前面。MergeTree 表数据的存储顺序就是按照 ORDER BY 字段顺序存储的,因为ck采用的是稀疏索引,所以定义合适的 ORDER BY 字段对于查询效率尤为重要。默认情况下ck的主键不能为空,可以通过设置allow_nullable_key选项,允许主键为空,但是强烈建议不要这样做,尤其在<= 21.8版本中,可能会导致数据库崩溃。

如图1,有一个ORDER BY CounterID, Date 的 MergeTree表,ck在存储数据的时候首先按照ORDER BY顺序存储数据,然后按照等距(图1是每七条记录)采样一组主键元素,并把采样数据单独保存为一个文件。这样在查询的时候只需要先在主键数据文件进行查找,找到对应块的偏移距离,然后按照偏移量到数据文件中对应的块查找就可以了。例如,查找 CounterID in (‘a’, ‘h’) 的数据,会首先检索出 0、1、2、6、7号块的数据,然后再筛选2、6、7块中符合条件的数据(0、1块数据显然都是符合的)。SAMPLE BY 采样字段,一般在对数据结果准确性要求不高的时候使用,比如计算平均值,如果数据量较大,只会对定义的采样字段采样数据计算,但是采样字段必须定义在主键中,如 SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))。TTL 定义数据有效期,和redis类似,redis作为缓存服务器可以存储具有时间有效期特性的数据,如验证码数据。ck可以定义列级TTL,也可以定义表级TTL,如果是列级TTL,则该列值到期后会被置为默认值,如果所有列都到期,则删除,注意TTL列不能作为键,创建TTL列表:

CREATE TABLE example_table
(
    d DateTime,
    a Int TTL d + INTERVAL 1 MONTH,
    b Int TTL d + INTERVAL 1 MONTH,
    c String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d;

相对于列级TTL,一般更常用表级TTL,可用来存储对历史数据不再关注的数据,而且表TTL可以把过期数据移动到磁盘或者卷(关于卷和磁盘的区别参见10),例如在训练模型进行在线迁移学习的时候,会一直使用新数据优化模型,不再关注历史数据等。创建表级TTL表:

CREATE TABLE example_table
(
    d DateTime,
    a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d + INTERVAL 1 MONTH [DELETE],
    d + INTERVAL 1 WEEK TO VOLUME 'aaa',
    d + INTERVAL 2 WEEK TO DISK 'bbb';

SETTINGS 用来设置一些附加参数,大多数情况下都不需要设置,可能用到的参数如下:index_granularity 索引粒度(按行),默认是8192,即每8192行数据采样一条索引数据,例如,图1的索引粒度是7.index_granularity_bytes 索引粒度(按字节),默认是10Mb,表示自适应间隔大小的特性,即根据每一批写入数据的体量大小,动态划分间隔大小。min_index_granularity_bytes 允许的最小索引粒度(按字节),默认值是 1024 b,防止意外地创建index_granularity_bytes非常小的保护机制。enable_mixed_granularity_parts 开启或者关闭index_granularity_bytes ,对于行数据很大的表,开启此选项可提升查询效率。storage_policy (存储策略):MergeTree家族表引擎可以在多个块设备上存储数据,这对于区分冷热场景的数据查询降低成本非常有用。例如,对于电商数据,最近半年的数据查询频率会比较高,响应要快,可以使用SSD存储,半年以上的数据(长尾数据),查询很少,可以响应慢一些,也就是可以使用低成本的存储介质,如HDD。
在继续介绍之前,首先区分几个概念:
① disk(磁盘):挂载到文件系统的块设备。
② default disk:服务器中指定的存储路径。
③ volume(卷):相同disk的有序集合,类似于JBOD。
④ Storage policy(存储策略):一组volume以及在volume之间移动数据的规则。
ck支持设置按照分区移动数据,也可以通过alter语句手动执行:

ALTER TABLE hits MOVE PART '20190301_14343_16206_438' TO VOLUME 'slow'
ALTER TABLE hits MOVE PARTITION '2019-09-01' TO DISK 'fast_ssd'

如果想通过配置实现数据的自动转移,可参考官方文档在配置文件中设置。
关于ck服务器的存储策略和资源信息可通过 system.storage_policies 和 system.disks 表查看。

min_bytes_for_wide_part, min_rows_for_wide_part 数据文件中可以以宽格式存储的最小字节/行数。宽格式指不同的列存储在不同的文件中,这也是默认的存储格式,对于一些小表,可以设置该值,使得所有列存储在同一个文件中,从而增加小而频繁的插入性能。max_partitions_to_read 限制一个查询中可以访问的最大分区数,默认是不限制。 4. MergeTree表数据存储结构

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/784195.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号