一般我们在存储例如用户信息的时候,用户信息的各属性是固定的,这时我们可以通过如下方式设计表:
user(user_id, name, age, sex)
但是,如果某天呢,产品说用户信息需要加几个属性:height、weight。
此时,如果表没什么数据当然是想加直接加上就行了,代码中跟着添加几个字段就OK了。但是如果数据量和并发量特别大怎么办?
alter table add column是不行的,因为锁表时间会很长。
这里说一种key+value的存储方式实现方法,此时表设计为:
user(user_id, key, value)
表里数据样式为:
user_id | key | value |
---|---|---|
1 | name | 张三 |
1 | age | 50 |
1 | sex | 男 |
1 | height | 170 |
1 | weight | 120 |
2 | name | 小胖呆 |
2 | age | 30 |
2 | sex | 男 |
这种将一行存储的数据拆成在一列里面存储的方式就是key+value动态字段存储。
key+value存储方式优缺点
优点:
可以随时动态扩展字段属性
缺点:
1) key值有大量冗余。建议key短一些
2) 行数会增加很多
3)索引设计可能比较麻烦
key+value存储方式使用场景
服务端,wordpress,EAV,配置,统计项、APP或者PC客户端、保存个人信息等等
key+value应用场景之——自定义页面功能设计
在有些系统中,可能会有这样一个需求:用户可以自定义某个页面的表单个数及样式。至于样式的自定义怎么实现,不是这里要说的,这里只说说关于表单个数的自定义实现。
在这种需求里,你不会知道用户到底会定义多个表单,这样你就不能在一张表里固定字段的个数。这时就可以利用key+value方式实现。
我们模拟一个业务场景:系统中有一个作物信息采集页面,每个种植公司可根据自己的需求设置不同的表单;例如公司A希望该页面能收集:作物品种、种植地块、作物高度、有无草害、有无虫害;而公司B则希望收集:作物品种、种植地块、当时田间温度、采集时间。
先设计出如下几张表(只有关键的字段):
模(mu)板表:model(id, model_name, company_id)
字段描述分别是:主键、模板名称、公司ID
模板部件表:model_parts(id, key_name, label, required, type, model_id)
字段描述分别是:主键、表单name,表单里的label、是否必填、类型(数字或字符串)、模板ID
作物信息采集表: crop_info(id, key, value, company_id, model_id)
字段描述分别是:主键、表单name,表单值,公司ID,模板ID
接着给各表添加数据:
模板表(model)需要管理员添加数据:
id | model_name | company_id |
---|---|---|
1 | 玉米数据采集模板 | 100 |
2 | 土豆数据采集模板 | 101 |
部件表(model_parts):在作物采集页面显示的都是来源于部件表的数据。
id | key_name | label | required(1:必填,0:非必填) | type(1:数字,2:字符串) | model_id |
---|---|---|---|---|---|
1 | category | 作物品种 | 1 | 2 | 1 |
2 | land_name | 种植地块 | 1 | 2 | 1 |
3 | height | 作物高度 | 1 | 1 | 1 |
4 | grass | 有无草害 | 1 | 1 | 1 |
5 | insect | 有无虫害 | 1 | 1 | 1 |
6 | category | 作物品种 | 1 | 2 | 2 |
7 | land_name | 种植地块 | 1 | 2 | 2 |
8 | temperatrue | 田间温度 | 1 | 2 | 2 |
9 | collect_time | 采集时间 | 1 | 2 | 2 |
作物采集表: crop_info
id | key | value | company_id | model_id |
---|---|---|---|---|
1 | category | 玉米 | 100 | 1 |
2 | land_name | 地块一 | 100 | 1 |
3 | height | 120 cm | 100 | 1 |
4 | grass | 有 | 100 | 1 |
5 | insect | 无 | 100 | 1 |
6 | category | 土豆 | 101 | 2 |
7 | land_name | 江家湾地块 | 101 | 2 |
1 | temperatrue | 36.5 | 101 | 2 |
1 | collect_time | 2018-10-10 | 101 | 2 |
以上所有遵循正规的表设计,这里只是提供一个思路
作物采集表就完全体现了key+value动态存储的思想。