clickhouse—如何避免合并分布式表上的高基数子选择聚合

qxsslcnc  于 2021-07-15  发布在  ClickHouse
关注(0)|答案(1)|浏览(493)

在clickhouse中,我有一个大表,表中有以下列:

date, user_id, operator, active

在表a中,事件已经在日期、用户id和运算符上进行了预聚合,而列“active”表示在给定日期存在某种用户活动。
表a分布在2个shard/服务器上:首先我在每个服务器上创建了表a\u local(pk是date,user\u id)。然后我创建了一个分布式表a,通过使用hash(userid,operator)作为分片键来合并本地表a\u local。user\u id是高基数字段(数千万到数亿),而列“operator”的基数较低(大约1000个不同的值)。每个用户id都属于一个操作符,也就是说tuple(用户id,操作符)与用户id本身具有相同的基数。
我需要计算每个运营商的用户数已经活跃超过n天,在一个给定的时期。为了实现这一点,我首先需要为每个用户查找用户在给定时间段内处于活动状态的天数,我在subselect中会这样做。然后,在main select中,我对按操作符分组的用户进行计数。

SELECT
    operator,
    count() AS cnt_user
FROM
(
    SELECT
        user_id,
        operator,
        count() AS cnt
    FROM A
    WHERE date >= '2019-06-01' AND date <= '2019-08-31'
    AND active = 1
    GROUP BY
        user_id,
        operator
    HAVING cnt >= 30
)
GROUP BY operator

使用用户id和操作符进行分片的思想是让用户路由到不同的分片。这样,我希望完整的查询(select和subselect)可以在每个shard/服务器上独立运行,然后在较小的基数集上执行最终聚合:operator->count。
但是,当我长时间(几个月)运行此查询时,clickhouse抛出异常,指出超出了最大查询内存分配。如果对本地表运行相同的查询,则不会出现此类异常,并返回结果。clickhouse首先合并两个shard上subselect的所有记录,然后计算外部聚合。问题是如何重写查询或/和更改模式,以便强制clickhouse在本地执行两个聚合,然后在最后一步合并低基数聚合(over操作符)?我希望在用户id和操作员上使用shard键可以让clickhouse自然地做到这一点,但事实似乎并非如此。

unftdfkk

unftdfkk1#

在每个碎片上

create view xxx as 
SELECT
        user_id,
        operator,
        count() AS cnt
    FROM A_local

    GROUP BY
        user_id,
        operator
    HAVING cnt >= 30

create xxx_d Distributed(,xxx);

select .... 
from xxx_d  
WHERE date >= '2019-06-01' AND date <= '2019-08-31'
            AND active = 1 
GROUP BY operator
settings distributed_group_by_no_merge=1

相关问题