知识点概要
- Broadcast/Shuffle Join
- 聚合模型的select count(*) 效率很低
分桶
分桶列的选择,是在 查询吞吐 和 查询并发 之间的一种权衡:
- 如果选择多个分桶列,则数据分布更均匀。如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合大吞吐低并发的查询场景。
- 如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的IO影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。
单个 Tablet 的数据量理论上没有上下界,但建议在 1G - 10G 的范围内。如果单个 Tablet 数据量过小,则数据的聚合效果不佳,且元数据管理压力大。如果数据量过大,则不利于副本的迁移、补齐,且会增加 Schema Change 或者 Rollup 操作失败重试的代价(这些操作失败重试的粒度是 Tablet)。
各种join
- broadcast join
- shuffle join
- Bucket Shuffle Join
- Colocate Join
举个例子,当前存在A表与B表的Join查询,它的Join方式为HashJoin,不同Join类型的开销如下:
- Broadcast Join: 如果根据数据分布,查询规划出A表有3个执行的HashJoinNode,那么需要将B表全量的发送到3个HashJoinNode,那么它的网络开销是
3B
,它的内存开销也是3B
。 - Shuffle Join: Shuffle Join会将A,B两张表的数据根据哈希计算分散到集群的节点之中,所以它的网络开销为
A + B
,内存开销为B
。
Runtime Filter
针对join查询的关联条件,添加运行时过滤器,减少数据扫描和计算的数量
doris存储文件和索引
bitmap全局字典
客户id | skuid | 销售额 |
---|---|---|
10001 | 123 | 10001123 |
客户id和skuid的组合非常多,所以排序和生成顺序号的时候单个节点压力非常大。所以需要考虑,如果对这些结果进行拆分,然后放到不同的task中进行排序和顺序号的生成。
两个维度的组合非常多,但是单个维度的值不多,所以可以先对单个维度(基于单个维度的维表)进行拆分,比如说都拆分成20份,这样组合之后是400份,可以放到400个task中执行。
遍历数据表中的所有记录,按照上述拆分的400份,将组合拆分到不同的分组中,然后到不同的task中并发的进行排序和顺序编号的生成。最终再将各个task的结果进行合并,当然还需要给顺序号添加一个偏移量
rollup
rollup与分区分桶
rollup是基于doris的物理存储文件来构建的,不会跨物理存储文件来聚合数据生成rollup,所以rollup是到分区+分桶级别的。不单单多个分区之间不能聚合rollup,一个分区的多个分桶下也不能聚合rollup
多表join时聚合多表的指标无法走rollup
1 | # bitmap_union_count(t65418_0.customer_id)/bitmap_union_count(t1000001773_2.customer_id) `cust_cover_rate_930749`指标计算的时候,计算字段位于两张表中,导致两个表都不能走rollup |
在子查询中先group by,然后对结果在join,子查询是可以走rollup的
1 | select |
函数对rollup的影响
聚合函数中增加if函数,会导致无法走rollup
1 | explain SELECT |
聚合函数中增加case when函数,可以走rollup
1 | explain SELECT |
cube与union all
cube(包括:grouping set),在doris中查询性能非常差,不管是粗粒度的聚合还是细粒度聚合到粗粒度的聚合,性能都很差。
实际查询中,需要将各种维度组合的sql生成好,然后再union all到一起进行查询,union all的时候注意多个sql最外层的查询字段的顺序的一致性。