• ClickHouse Projection


    前面我们介绍MergeTree引擎的时候,唯独建表语句中的 PROJECTION 定义项没有介绍,在了解完二级索引和物化视图后,本篇文章就来细说一下这个非常重要的功能。

    在创建MergeTree表的时候可以定义ORDER BY字段,如果基于ORDER BY字段查询,速度会很快,但是ORDER BY字段是固定的,一旦查询非ORDER BY字段或者不是按照ORDER BY字段顺序查询,效率都会降低。此时,我们可以创建二级索引(跳数索引)或者物化视图等,但是二级索引只是一些粗粒度的索引,例如min/max等,而物化视图数据是独立存储的,无法感知删除操作,还会拖累原表写入性能。针对这种情况,ClickHouse还提供了另外一个新功能——Projection。(Projection是ClickHouse 21.6才有的新特性,使用的时候需要注意版本支持。)

    Projection类似物化视图但是是part-level存储,在一张表的分区子目录里面有一个独立的projection数据存储,也就是说它和原表分区在一起,数据是同源的,而且提供了一致性保证。这也就意味着如果原表的数据变了,那么projection也会发生变化。其次,projection的使用是无感的,它更像是原表的一个智能索引,对一张表可以创建很多个projection,在查询时会根据算法去自动匹配。如果能匹配上,就用一个最优的projection提供查询加速,如果没有命中还是查原表。有了这些特性以后,projection比使用物化视图方便非常多。

    ※注意:带有FINAL修饰符的SELECT语句不支持projection。

    projection优化默认是不开启的,有两个配置项需要设置:

    • allow_experimental_projection_optimization:在处理SELECT查询时启用或禁用projection优化,0禁止,1开启,默认是0。
    • force_optimize_projection:当开启projection优化时,启用或禁用在SELECT查询中强制使用projection,0不强制使用,1强制使用,默认是0。

    创建projection有两种方法,第一种是在建表的时候定义,第二种是在后期添加:

    -- 建表指定
    CREATE TABLE table_name 
    (
        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 p1 (SELECT WatchID, Title ORDER BY WatchID),
        PROJECTION p2 (SELECT UserID, SearchPhrase, count() GROUP BY UserID, SearchPhrase)
    ) ENGINE = MergeTree()
    ORDER BY ...
    PARTITION BY ...;
    
    -- ALTER添加
    ALTER TABLE table_name ADD PROJECTION p1
    (
        SELECT 
            WatchID, Title
        ORDER BY WatchID
    );
    ALTER TABLE table_name ADD PROJECTION p2
    (
        SELECT 
            UserID, SearchPhrase, count()
        GROUP BY UserID, SearchPhrase
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    再来看一下table_name的底层文件存储结构。
    projection目录结构
    可以发现在对应的分区目录下,多了一个projection子目录,而且目录中的文件内容和外部原表的数据存储结构非常像,只是没有元数据信息。此时,projection的原理就基本明了了。projection基于定义维护了一份独立的数据存储,但是因为是跟踪原表分区目录存在的,所以不需要保存元数据信息。如果projection的定义语句是ORDER BY,则projection的子目录存储引擎就是MergeTree,如果projection的定义语句是GROUP BY,底层存储引擎变成AggregatingMergeTree,所有聚合函数都转换为AggregateFunction。当在查询中,能匹配到的projection时,就会使用部分预处理好的数据直接返回,这也正是projection加速的本质。例如可以定义一个包含GROUP BY的聚合projection,对于明细数据可以直接查原表,聚合数据通过projection获得。

    目前projection不支持跨表操作,所以对于有跨表的预聚合的场景,例如join,还是要利用物化视图。

  • 相关阅读:
    自己亲手打造的VS Code里写AsciiDoc的快捷模板Snippet文件
    嵌入式开发-11 Linux下GDB调试工具
    [数据库与软件工程]四、关系代数之关系除法的实际意义与计算方法
    二十三种设计模式全面解析-适配器模式的妙用:异构数据库和不同版本API的完美兼容!
    在Linux操作系统的ECS实例上安装Hive
    全新整合热搜榜单热门榜单内容系统聚合源码/带教程安装
    Linux服务器部署Spring Boot项目的一些shell命令脚本
    Apache log4j漏洞总结
    第4周学习:MobileNetV1, V2, V3
    端子排中间继电器WZY-400W
  • 原文地址:https://blog.csdn.net/haveanybody/article/details/126285494