我们完成了一般的积分系统表模型设计,也的确可以满足大部分企业的业务诉求。但是我们不妨想一想,积分签到信息一个用户、一个月可能会产生0-28/29/30/31的数据条目,按30来算一年就是360条数据,一条数据大小按我们刚才的表结构设计,我们来看看会占用多少字节数
表字段 | 数据类型 | 占用字节数 |
id | bigint | 8 |
user_id | bigint | 8 |
year | year | 1 |
month | tinyint | 1 |
date | date | 3 |
is_backup | bit | 1 |
合计:22 个字节 |
所以,上面的表结构可以存,但是面对大业务量的时候,就会因数据存储问题导致查询效率变慢,或需要做分库分表了。
做模型设计时,不仅考虑能不能存,最好多思考一下:这样存,后面会不会出现什么问题?
那么有什么数据结构是比较适合的呢?实际这里比较适合位图
的存储结构,就类似我们的签到卡,当用户签到我们记录1,没签到记录0
把每一个bit位对应当月的每一天,形成了映射关系。用0和1标示业务状态,这种思路就称为位图(BitMap)
如布隆过滤器就是借助位图实现的。
最终我们的记录在一个月后会变成:
数据一下子就减少了很多内存(仅31bit),并且一个月才一条数据,但是随之而来的问题就是,位图怎么存 ?怎么取?实际Redis中提供了BitMap数据结构(底层还是String数据结构),并且提供了很多操作bit的命令。
Redis指令学习
- 存储数据指令:SETBIT
指令是:
- SETBIT:关键字
- key:存储的key
- offset:存储的位置脚标,0开始
- value:存储的值
- 读取数据指令:BITFIELD
指令是:
- BITFILED:关键字
- key:存储的key
- GET:关键字
- encoding:编码格式+要读取几位,u:无符号整数(常用)、i:有符号整数
- offset:从哪个脚标开始读取
Redis指令测试
由于我们的redis是部署在docker中的,所以步骤大致如下:
- 进入容器的指令:
docker exec -it redis redis-cli
进入 - 存储数据:
setbit user 0 1
,会提示没有权限,我们输入一下密码:auth 123321
,再存储就可以了
这里的返回值,说明的是存储在当前脚标下,之前的值是多少,因为默认都是0,所以返回0,我们再存一次会发现返回的是1
- 我们可以多存储几个,甚至可以跳着存储(模拟部分天数打卡,部分不打卡),也会发现格式不对会失败
我们此时数据存储是:111010001
- 查看数据:
BITFIELD user GET u2 2
:从脚标2开始获取长度2的数据,即获取脚标为2-3的数据,数据的key是 user,而脚标为2-3的数据在上面可以发现是1 0,并且二进制中:10标识的是2,因此返回:2
- 同理,我们如果是从脚标0开始,获取3位,即:111,在二进制就是:7(1+2+4)
- 所以后续我们就可以使用:
SETBIT
,BITFIELD
完成签到数据的保存和读取了。
- 最后取出来的数据进行后面向前的唯一运算就能得到连续打卡天数了.