一个会员标签的存储和检索需求
发布于 2 个月前 作者 catchex 392 次浏览 来自 问答

我有一个场景,会员+会员标签(超过2000个)存储在一张表。 我的想法: 通过创建两千个字段不行,由于ClickHouse 里没有Binary 类型,只能通过Array 存储。 但Array 的查询效率太低了,通过arrayElement(tag, 1) = a_tag AND arrayElement(tag, 1) = a_tag 这样的查询效率太低,在几千万的表里超过10秒才出结果。

4 回复

如果设法转成位操作,应该会快很多。

为每个会员创建 2500/64个 Int64列,大概50列C1…C50左右。

插入记录时,所有tag列的默认值为0.

插入时根据用户的标签计算出哪些列需要设置。 比如该用户有第140个,160个标签,那么140 % 64 + 1,即第3列的第12位为1, 第32位为1。

查询时,根据查询标签构造查询条件,比如: where bitXor(c3, 0b1000000000000) = 1

多条件也照此办理。

而且 where bitXor(c3, 0b1000000000000) 这样的查询效率不够高,无法用到索引。数据量大了,依然很慢

还有一种方案,需要应用层配合。 为每个tag创建表,例如tag1,tag2,…tagn 每个表只有1列,用户id, ORDER BY id。

插入用户时,把用户的所有tag的表都插入一条记录。 比如用户1001拥有tag 1, 57, 323, 那么往tag1, tag57, tag323中插入1001这条记录。

查询场景1:搜索某个用户xyz的所有tag select id from tag1 where id = xyz; … select id from tagn where id = xyz; 汇总以上记录即可。由于按id排序,上述查询会很快。

查询场景2:搜索具有tagi, tagj, tagk, …的所有用户。 就是对表tagi, tagj, tagk, …做连接查询。 由于按id排序,连接查询速度会很快。 千万级别的表,一般PC机到不了一秒。

上述查询都用上了ck的主键,能获得最佳的性能。

缺点:需要应用层配合,构造语句,聚合结果。

试试看

回到顶部