• ClickHouse优化(建表、配置)


    1.数据类型

    1.1时间字段的类型

    建表时能用数值型或日期时间型表示的字段就不要用字符串,全 String 类型在以 Hive为中心的数仓建设中常见,但 ClickHouse 环境不应受此影响。
    虽然 ClickHouse 底层将 DateTime 存储为时间戳 Long 类型,但不建议存储 Long 类型,因为 DateTime 不需要经过函数转换处理,执行效率高、可读性好。
    CREATE TABLE t_type2
    (
        `id` UInt32,
        `sku_id` String,
        `total_amount` Decimal(16, 2),
        `create_time` Int32
    )
    ENGINE = ReplacingMergeTree(create_time)
    PARTITION BY toYYYYMMDD(toDate(create_time)) —-此处需要转换成时间类型
    PRIMARY KEY id
    ORDER BY (id, sku_id);
     
    CREATE TABLE t_type3
    (
        `id` UInt32,
        `sku_id` String,
        `total_amount` Decimal(16, 2),
        `create_time` DateTime
    )
    ENGINE = ReplacingMergeTree(create_time)
    PARTITION BY toYYYYMMDD(create_time)
    PRIMARY KEY id
    ORDER BY (id, sku_id);
     

    1.2空值存储类型

    官方已经指出 Nullable 类型几乎总是会拖累性能,因为存储 Nullable 列时需要创建一个额外的文件来存储 NULL 的标记,并且 Nullable 列无法被索引。因此除非极特殊情况,应直接使用字段默认值表示空,或者自行指定一个在业务中无意义的值(例如用-1 表示没有商品ID)。
    date1002 :) CREATE TABLE t_null(x Int8, y Nullable(Int8)) ENGINE TinyLog;
    CREATE TABLE t_null
    (
        `x` Int8,
        `y` Nullable(Int8)
    )
    ENGINE = TinyLog
    Query id: 4a313cb8-86a7-4bf0-99a9-16a945e665ac
    Ok.
    0 rows in set. Elapsed: 0.003 sec. 
     
    date1002 :) INSERT INTO t_null VALUES (1, NULL), (2, 3);
    INSERT INTO t_null FORMAT Values
    Query id: ebd34cde-af7a-46e4-8956-b2ddc8afc09b
    Ok.
    2 rows in set. Elapsed: 0.002 sec. 
     
    date1002 :) SELECT x + y FROM t_null;
    SELECT x + y
    FROM t_null
    Query id: fe7448ca-2147-43ac-8afe-725852577fe0
    ┌─plus(x, y)─┐
    │       ᴺᵁᴸᴸ │
    │          5 │
    └────────────┘
     
    查看存储的文件
    [root@date1002 ~]# cd /var/lib/clickhouse/data/default/t_null/
    [root@date1002 t_null]# ll
    总用量 16
    -rw-r----- 1 clickhouse clickhouse 95 4月  20 22:06 sizes.json
    -rw-r----- 1 clickhouse clickhouse 28 4月  20 22:06 x.bin
    -rw-r----- 1 clickhouse clickhouse 28 4月  20 22:06 y.bin
    -rw-r----- 1 clickhouse clickhouse 28 4月  20 22:06 y.null.bin
    y字段可以为null的话,会有一个文件单独存储null值
     

    2.分区和索引

    分区粒度根据业务特点决定,不宜过粗或过细。一般选择按天分区,也可以指定为 Tuple(),以单表一亿数据为例,分区大小控制在 10-30 个为最佳。
    必须指定索引列,ClickHouse 中的索引列即排序列,通过 order by 指定,一般在查询条件中经常被用来充当筛选条件的属性被纳入进来;可以是单一维度,也可以是组合维度的索引;通常需要满足高级列在前、查询频率大的在前原则;还有基数特别大的不适合做索引列,如用户表的 userid 字段;通常筛选后的数据满足在百万以内为最佳。
     
    比如官方案例的 hits_v1 表:
    ……
    PARTITION BY toYYYYMM(EventDate)
    ORDER BY (CounterID, EventDate, intHash32(UserID))
    ……
    visits_v1 表:
    ……
    PARTITION BY toYYYYMM(StartDate)
    ORDER BY (CounterID, StartDate, intHash32(UserID), VisitID)
    ……
     

    3.表参数

    Index_granularity 是用来控制索引粒度的,默认是 8192,如非必须不建议调整。
    如果表中不是必须保留全量历史数据,建议指定 TTL(生存时间值),可以免去手动过期历史数据的麻烦,TTL 也可以通过 alter table 语句随时修改。
     

    4.写入和删除优化

    (1)尽量不要执行单条或小批量删除和插入操作,这样会产生小分区文件,给后台Merge 任务带来巨大压力
    (2)不要一次写入太多分区,或数据写入太快,数据写入太快会导致 Merge 速度跟不上而报错,一般建议每秒钟发起 2-3 次写入操作,每次操作写入 2w~5w 条数据(依服务器性能而定)
     
    写入过快报错,报错信息:
    1. Code: 252, e.displayText() = DB::Exception: Too many parts(304).Merges are processing significantly slower than inserts
    2. Code: 241, e.displayText() = DB::Exception: Memory limit (for query) exceeded:would use 9.37 GiB (attempt to allocate chunk of 301989888 bytes), maximum: 9.31 GiB
    处理方式:
    Too many parts 处理:使用 WAL 预写日志,提高写入性能。
    in_memory_parts_enable_wal 默认为 true
    在服务器内存充裕的情况下增加内存配额,一般通过 max_memory_usage 来实现
    在服务器内存不充裕的情况下,建议将超出部分内容分配到系统硬盘上,但会降低执行速度,一般通过 max_bytes_before_external_group_by、max_bytes_before_external_sort 参数来实现。
     

    5.常见配置

    配置项主要在 config.xml 或 users.xml 中, 基本上都在 users.xml 里
    config.xml配置项(服务端配置)
    users.xml配置项(可用最大内存配置等,大部分配置在users.xml)
     

    5.1CPU资源

    background_pool_size:后台线程池的大小,merge 线程就是在该线程池中执行,该线程池不仅仅是给 merge 线程用的,默认值 16,允许的前提下建议改成 cpu 个数的 2 倍(线程数)。
    background_schedule_pool_size:执行后台任务(复制表、Kafka 流、DNS 缓存更新)的线程数。默认 128,建议改成 cpu 个数的 2 倍(线程数)。
    background_distributed_schedule_pool_size:设置为分布式发送执行后台任务的线程数,默认 16,建议改成 cpu个数的 2 倍(线程数)。
    max_concurrent_queries:最大并发处理的请求数(包含 select,insert 等),默认值 100,推荐 150(不够再加)~300。
    max_threads:设置单个查询所能使用的最大 cpu 个数,默认是 cpu 核数
     

    5.2内存资源

    max_memory_usage: 此参数在 users.xml 中,表示单次 Query 占用内存最大值,该值可以设置的比较大,这样可以提升集群查询的上限。保留一点给 OS,比如 128G 内存的机器,设置为 100GB。
    max_bytes_before_external_group_by:一般按照 max_memory_usage 的一半设置内存,当 group 使用内存超过阈值后会刷新到磁盘进行。因为 clickhouse 聚合分两个阶段:查询并及建立中间数据、合并中间数据,结合上一项,建议 50GB。
    max_bytes_before_external_sort :当 order by 已使用 max_bytes_before_external_sort 内存就进行溢写磁盘(基于磁盘排序),如果不设置该值,那么当内存不够时直接抛错,设置了该值 order by 可以正常完成,但是速度相对存内存来说肯定要慢点(实测慢的非常多,无法接受)。
    max_table_size_to_drop: 此参数在 config.xml 中,应用于需要删除表或分区的情况,默认是50GB,意思是如果删除 50GB 以上的分区表会失败。建议修改为 0,这样不管多大的分区表都可以删除。
     

    5.3存储

    ClickHouse 不支持设置多数据目录,为了提升数据 io 性能,可以挂载虚拟卷组,一个卷组绑定多块物理磁盘提升读写性能,多数据查询场景 SSD 会比普通机械硬盘快 2-3 倍。
     
     
     
     
  • 相关阅读:
    Post提交和Get提交的区别
    Servlet 生命周期
    MVC
    HDU 5033 Building (维护单调栈)
    2014 ACM/ICPC Asia Regional Xi'an Online(HDU 5007 ~ HDU 5017)
    HDU 1026 Ignatius and the Princess I (BFS)
    URAL 1183 Brackets Sequence(DP)
    POJ 3384 Feng Shui(半平面交向内推进求最远点对)
    POJ 3525 Most Distant Point from the Sea (半平面交向内推进+二分半径)
    POJ 1279 Art Gallery(半平面交求多边形核的面积)
  • 原文地址:https://www.cnblogs.com/EnzoDin/p/16172215.html
Copyright © 2020-2023  润新知