V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wenjun19931112
V2EX  ›  ClickHouse

我这个场景, clickhouse 适用吗?

  •  
  •   wenjun19931112 · 2021-06-03 11:17:26 +08:00 · 5205 次点击
    这是一个创建于 1298 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如求每个客户的“平均购买力”。 我们表设计 3 个字段 ( userId,orderId,price )。 但是 price 可能会变动,这条记录会被删除(业务原因)。

    为了支持 update\delete,我们选择版本折叠树。 主键设置 (userId,orderId)两个字段。 但是我的统计维度却只要 userId (求每个客户的“平均购买力”),如果通过一个维度去聚合 “版本折叠树”,得到的数据又是不准确的。

    有什么办法吗?

    15 条回复    2021-06-03 14:30:21 +08:00
    leiuu
        1
    leiuu  
       2021-06-03 11:45:10 +08:00
    1. 为什么结果是不准确的 这里没太理解
    2. 如果你的描述我理解没错的话 好多 olap 引擎都可以支持这类的聚合统计的 数据不大甚至可以用 mysql (这里可能是我想简单了)
    weizhen199
        2
    weizhen199  
       2021-06-03 11:53:48 +08:00 via Android
    表更新频率数据量?
    wenjun19931112
        3
    wenjun19931112  
    OP
       2021-06-03 12:44:09 +08:00
    @weizhen199
    数据量至少是千万级别,更新频率不算太高
    wenjun19931112
        4
    wenjun19931112  
    OP
       2021-06-03 12:44:41 +08:00
    @leiuu
    因为 版本折叠树 需要 group by 主键,聚合出来的数据才是准确的
    liuhuansir
        5
    liuhuansir  
       2021-06-03 12:51:18 +08:00
    @wenjun19931112 千万级别不需要 clickhouse 吧?我们都是百亿级别的数据,监控类数据,不存在更新
    PiersSoCool
        6
    PiersSoCool  
       2021-06-03 13:09:40 +08:00   ❤️ 2
    olap 的数据库都不太支持更新 会影响性能
    leiuu
        7
    leiuu  
       2021-06-03 13:13:44 +08:00
    我试了下结果是符合预期的呢,
    ```sql
    CREATE TABLE user_order_price
    (
    userId UInt64,
    orderId UInt8,
    price Float64,
    sign Int8,
    version UInt8
    )
    ENGINE = VersionedCollapsingMergeTree(sign, version)
    ORDER BY (userId,orderId)



    INSERT INTO user_order_price VALUES (101, 10000, 100, 1, 1),(101, 10000, 100, -1, 2),(102, 10000, 200, 1, 2)



    INSERT INTO user_order_price VALUES (103, 10000, 500, 1, 2)



    SELECT
    userId,
    sum(price * sign) AS avgPrice
    FROM user_order_price
    GROUP BY userId

    ```
    结果不准确是指哪个位置
    wenjun19931112
        8
    wenjun19931112  
    OP
       2021-06-03 13:31:01 +08:00
    @leiuu
    sql 中 `group by userId`,但是你的主键是( userId,orderId )。那么 sql 不是按主键对应折叠,`avgPrice`会不对。
    数据正确的写法是 `group by userId,orderId`
    wenjun19931112
        9
    wenjun19931112  
    OP
       2021-06-03 13:31:55 +08:00
    @liuhuansir
    考虑到后期的数据增长,数据上亿是很快的。
    wenjun19931112
        10
    wenjun19931112  
    OP
       2021-06-03 13:33:28 +08:00
    我找到了一个新的写法,搜索之前使用 final 去合并。因为据说现在 final 的性能已经比较好了。
    比如:
    SELECT
    userId,
    sum(price * sign) AS avgPrice
    FROM user_order_price FINAL
    GROUP BY userId

    https://cloud.tencent.com/developer/article/1662230
    wenjun19931112
        11
    wenjun19931112  
    OP
       2021-06-03 13:34:40 +08:00
    wenjun19931112
        12
    wenjun19931112  
    OP
       2021-06-03 13:56:50 +08:00
    @leiuu
    我想错了,group by 没有说要求一定要是主键
    leiuu
        13
    leiuu  
       2021-06-03 14:09:08 +08:00
    👍 查询中使用 final 关键词确实是一个折衷的较好的方法: https://clickhouse.tech/docs/en/sql-reference/statements/select/from/#select-from-final


    这里还要正好探讨下:
    ```
    SELECT
    userId,
    sum(price * sign) AS avgPrice
    FROM user_order_price
    GROUP BY userId
    ```
    这个 sql 其实和折叠数关系不大,你的场景中 price 都是正数的情况下,结果应该是对的,和是否使用全部主键关系不大,不过这里也可能我理解错误。

    另外如果相同 userId 的数据分散在不同物理机上,那结果可能是不对的(未做验证)。
    leiuu
        14
    leiuu  
       2021-06-03 14:10:21 +08:00
    对的 对主键没要求的 😂
    wenjun19931112
        15
    wenjun19931112  
    OP
       2021-06-03 14:30:21 +08:00
    @leiuu
    1 、我测试了一下。price 是负数也不影响结果。
    2 、我认为和数据分布在不同机器上没关系。假设不考虑自动折叠,我认为用最普通的 mergetree 也能达到我要的效果( update `price`后保证 groupby 的聚合结果正确)。只要我人为的增加一个 sign 列就好了。
    3 、自动折叠,据看官方文档的了解只是为了节省空间。
    不知道我的理解是否正确。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2540 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 03:20 · PVG 11:20 · LAX 19:20 · JFK 22:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.