数据类型
时间字段的类型
建表时能用数值型或日期时间型表示的字段就不要用字符串
虽然ClickHouse底层将DateTime存储为时间戳Long类型,但不建议存储Long类型,因为DateTime不需要经过函数转换处理,执行效率高、可读性好 下面这个例子用了int32存日期, 这样存的话, 要用toDate转换下才能用, 效率低, 应该直接用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);
空值存储类型
官方已经指出Nullable类型几乎总是会拖累性能,因为存储Nullable列时需要创建一个额外的文件来存储NULL的标记,并且Nullable列无法被索引。因此除非极特殊情况,应直接使用字段默认值表示空,或者自行指定一个在业务中无意义的值(例如用-1表示没有商品ID)
CREATE TABLE t_null(x Int8, y Nullable(Int8)) ENGINE TinyLog;
INSERT INTO t_null VALUES (1, NULL), (2, 3);
SELECT x + y FROM t_null;
1 + NULL = NULL:
单独的文件来存储NULL值:
SELECT x + y
FROM t_null
Query id: 9fc5ca79-fdfb-47eb-b53c-361eda2f6c60
┌─plus(x, y)─┐
│ ᴺᵁᴸᴸ │
│ 5 │
└────────────┘
2 rows in set. Elapsed: 0.002 sec.
[root@aliyun ~]# cd /var/lib/clickhouse/data/default/t_null/
[root@aliyun t_null]# ll
total 16
-rw-r----- 1 clickhouse clickhouse 91 Sep 21 08:28 sizes.json
-rw-r----- 1 clickhouse clickhouse 28 Sep 21 08:28 x.bin
-rw-r----- 1 clickhouse clickhouse 28 Sep 21 08:28 y.bin
-rw-r----- 1 clickhouse clickhouse 28 Sep 21 08:28 y.null.bin
分区和索引
分区粒度根据业务特点决定,不宜过粗或过细。一般选择按天分区,也可以指定为Tuple(),以单表一亿数据为例,分区大小控制在10-30个为最佳
必须指定索引列,ClickHouse中的索引列即排序列,通过order by指定,一般在查询条件中经常被用来充当筛选条件的属性被纳入进来;可以是单一维度,也可以是组合维度的索引;
通常需要满足高级列在前、查询频率大的在前原则;
还有基数特别大的不适合做索引列,如用户表的userid字段;
通常筛选后的数据满足在百万以内为最佳
表参数
Index_granularity是用来控制索引粒度的,默认是8192,如非必须不建议调整 如果表中不是必须保留全量历史数据,建议指定TTL(生存时间值),可以免去手动过期历史数据的麻烦,TTL也可以通过alter table语句随时修改写入和删除优化
- 尽量不要执行单条或小批量删除和插入操作,这样会产生小分区文件,给后台Merge任务带来巨大压力
- 不要一次写入太多分区,或数据写入太快,数据写入太快会导致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
参数来实现
常见配置
配置项主要在config.xml或users.xml中,基本上都在users.xml里
config.xml的配置项:
https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings/
users.xml的配置项:
https://clickhouse.com/docs/en/operations/settings/settings/