在生鲜超市的高效运营中,实时数据分析至关重要。万象云鼎的“云鲜生”通过智能秤+网关+软件系统的组合,实现了销售数据的精准管理与优化,覆盖 260+ 客户、700+ 超市。而在数据处理方面,TDengine 的流计算能力成为了这一方案的核心支撑。本文详细分享了“云鲜生”如何利用 TDengine 高效存储和分析海量销售数据,在优化超市运营、提升用户体验的同时,解决高基数分组、高并发查询等技术挑战。

作者 | 万象云鼎研发团队 宋慧民 姜涛



create stream stream_billsale_daytrigger at_onceIGNORE EXPIRED 0fill_history 1into possum.billsale_dayTAGS (tenantid int,shopid int,userid int,stalltype int,productid bigint,subproductid bigint)SUBTABLE(CONCAT('saleday_', tbname))asselect _wstart as saledate,sum(cast(case when IsReturn=0 then qty else 0 end as bigint)) as saleqty,sum(cast(case when IsReturn=0 then money else 0 end as bigint)) as salemoney,sum(cast(case when IsReturn=1 then 0-qty else 0 end as bigint)) as refundqty,sum(cast(case when IsReturn=1 then 0-money else 0 end as bigint)) as refundmoney,max(price) as maxprice,min(price) as minprice,last(saletime) as lastsaletime,first(saletime) as firstsaletime from billsalePARTITION BY tbname,tenantid,userid,shopid,stalltype,productid,subproductidinterval (1d);
saleqty:日销售量,计算方式为将 IsReturn 为 0 的“销售量”字段求和。
salemoney:日销售额,计算方式为将 IsReturn 为 0 的“销售额”字段求和。
refundqty:日退货数量,计算方式为将 IsReturn 为 1 的“销售量”取负值后求和。
refundmoney:日退货金额,计算方式为将 IsReturn 为 1 的“销售额”取负值后求和。
maxprice:日最高价格。
minprice:日最低价格。
saledate:日窗口开始时间(_wstart)。
firstsaletime:日该商品第一次销售时间。
lastsaletime:日该商品最后一次销售时间。
在我们的实际应用中,由于商品种类繁多,商家众多 (覆盖 260+ 客户、700+ 超市),因此衍生出的标签也极为丰富。在对这些多字段全部进行分组之后,产生了典型的高基数问题,一共创建了 2600 万的子表。只有这样的分组,才能满足我们的全部分析需求,也就是说:灵活的背后是全量的覆盖。

和业务侧多方多次沟通讨论,在分组过程中,精简不需要的标签。
把流计算产生的数据,写入到另一个库中,这样就可以针对性的配置建库参数。由于我们的数据每天只有一条,我们将 duration 参数调整为 1825天,使得即便存储 5 年的全量数据,也可以只用一个数据文件承载,从而大幅优化存储效率。

大胆放开 VGROUPS 增加硬件增加并行度(实际值 400)。
由于我们对所有历史数据都进行了计算,因此我们的用户在任何时间都可以结合历史数据进行查询分析。




以上就是我们在使用 TDengine 过程中的一些心得与经验。作为一款出色的国产时序数据库,TDengine 在实际应用中真正地为我们智能生鲜行业提供了巨大帮助。遂整理成文,希望 TDengine 发展得越来越好,早日成为时序数据领域的 Oracle。

推荐阅读
从 taosX 优化到查询增强,TDengine 3.3.5.0 亮点抢先看!
25-1-7

24-12-31

24-12-12





