起源于我在一个短视频中分享的一道面试题,当然,这道面试题我确实在工作中用过,只是业务场景不同。
题目是:假设有这样一个需求场景,需要将所有用户的商品id
存储到redis
缓存,某个接口要求判断请求的商品id
是否在数据库中,也就是是否在redis
缓存中,请问你觉得使用哪种数据结构类型缓存商品id
最合适?
这道题考察面试者:
- 对
redis
数据结构类型的了解,能够根据业务场景使用合适的类型 bitmap
算法,也是考察算法- 遇到
id
值很大,即超过int
类型的最大值时,如何应对,即思维能力
1
某位朋友提问:
请教个问题,网上说bitmap常用来进行用户活跃度,签到的统计。它的bit
位也只能存储0
或1
,为什么用bitmap
能提升性能呢?
我的回答:
Set
集合查询时间复杂度是O(1)
,但是有Hash
冲突,可能带有链表的遍历,而bitmap
访问相当于数组下标。
bitmap只用
1bit存一个商品
id,在商品
id分布均匀情况下,节省的内存是存储商品
id字符串的多少倍?需求场景是只需判断一个商品
id是否在缓存中,那么
0和
1还不够吗?
setbit key 商品id 0/1
追问:
我懂了,命令SETBIT key offset value
,这里是将id
作为offset
使用,不同的id
对应不同的位,而不是作为key
使用,多谢解答[赞]。
另一位朋友作出的解答很好:
你确定bitmap
一定可以?我要是没记错key
范围是int
,很多id
都是long
。
我的解释:
确实[赞]。这时候就是下一个问题了。
key
不是只能有一个,可以用多个key
存储,这就是分桶的概念。假设第一个桶,也就是key1,用来
存1
到100000000
的id
,那么第二个桶就可以存100000000
到200000000
亿的id
,不过是先将id
减去100000000
。有没有必要分桶,主要还是看商品数量到一个什么级别,以及商品id的最大值。
2
某位朋友提问:
我们项目里用户id
是uuid
生成的14
位数值,本来想存bitmap
,想想还不如sql
统计登陆的日志呢[泪奔]
我的回答:
非整数类型用不了这种数据类型存储,可以借用布隆过滤器插件实现,但是有误差存在,需要确保误差不会影响正常业务。
一般都是使用自增主键。id
作为主键索引,使用自增主键比用uuid的插入性能高,这是索引B+树的知识点。
追问:
如果是分布式数据库用自增主键可能会有冲突吧?
我的回答:
分布式数据库可以用雪花算法等分布式 id生成算法,id
可以不是自增,但最好是保持增长的,单个数据库节点的单个表的主键确保是增长的。uuid这种太随机。
提问者的自我回答:
对,因为插入时候b+
数是按顺序向右扩展的。