数据库设计 - 同一张表不同类型的字段处理
问题描述:
在应用程序中拥有某种相同性质的类型, 在进行某些相似或相同的操作的时候展现出一样的行为. 但在某些字段上会予以区分
比如某个应用程序中有用户这个类, 用户大致可以进行注册, 登陆,充值等一系列操作, 而用户又是一个抽象的概念, 其中可以分为 企业用户, 个人用户等
所以, 以上所述, 吧问题归结为, 如何处理同一类型下不同子类的字段的问题

解决方案:
1. 最简单的解决方案, 就是将所有的字段都归集到同一张表上
优点是:这样在处理问题的时候逻辑最清晰, 查找, 添加, 索引也最方便
缺点就是建立了非常多冗余的字段, 造成数据库中大片大片的 NULL 值
另外表的字段也会过多, 非常的不优雅,
另外, 如果要在此基础上进行拓展, 那么需要直接在表上多加一个字段, 可能会影响到之前所有涉及到的数据的表现
最后, 如果将来某几个字段与此表的关系发生改变, 如需要变成1对多的情况, 将会十分的麻烦
场景描述
| 添加/编辑 |
public void Insert(User user) { Context.Add(user); } |
| 删除 |
public void Delete(int Id) { var user = Context.Delete(Id); Save(); } |
| 查找单例 |
public void Find(int Id) { var user = Context.Find(Id); } public void Find(string key) { var user = Context.SingleOrDefault(d => d.Key == key); } |
| 查找集合/筛选 |
public void FindSet() { Context.User; } public void FindSet(Func<> where) { Context.User.Where(where); } |
2.将各种字段按照性质进行抽离, 将字段集变为新表

这样的优点是, 逻辑清晰, 数据结构干净, 不会有大量冗余字段
将来拓展也很方便, 直接在某个表上面加字段或者直接建立新表即可, 不会影响到全局
这样做的缺点也很明显, 就是查找和添加会变得很麻烦
你需要关注到每个表, 查找的时候还需要多张表都建立关联
另外, 如果类目过多, 则表就会过多, 数据库会显得杂乱
3. ORM 独有的设计方式 (拿EF来举例)
就是应用程序内的继承

实际上, 在数据库中还是2张表,
但是在应用程序中处理, 则可以当一个对象来对待, 需要时则使用子类
这样做的好处很明显, 开发者不用关心数据库里的表结构如何, 只需关心应用程序里的实体
逻辑清晰, 操作带来一定的方便
缺点就是, 可能在某些相同应为上需要为不同的子类型使用相似但不同的方法
例如:
用户注册
public void Register(个人用户 user) { //姓名, 年龄, ... //个人用户Db.Save(); } public void Register(企业用户 user) { //营业执照, 组织机构代码 ... //企业用户Db.Save(); }
4. 行变列设计模式

将所有的行变为列来设计,
这样做的好处是非常的灵活, 不管需要未来加多少字段都不用改动数据库
也不会造成任何的字段冗余, 不会出现 NULL
缺点就是, 逻辑可能比较坳, 容易出现一些意想不到的问题
对于用户信息表来说可能数量庞大, 假设一个网站1亿用户, 一个用户有20条信息
那么这张表的数量会占20亿条
场景描述
| 添加/编辑 |
public void Insert(Model input) { var user = [input.Type, input.Username, input.Password...]; Context.User.Add(user); var infoA = [input.UserId, input.A]; Context.Info.Add(infoA); var infoB = [input.UserId, input.B]; Context.Info.Add(infoB); var infoC = [input.UserId, input.C]; Context.Info.Add(infoC); ...... Save(); } |
| 删除 |
public void Delete(int Id) { Context.User.Delete(Id); Context.Info.Delete(d => d.UserId == Id); } |
| 查找单例 |
public void Find(int Id) { var user = Context.User.Find(Id); var info = Context.Info .Where(d => d.UserId == Id) ToDictionary(k => k.Field, v => v.Value); } |
| 查找集合/筛选 |
public void FindSet(int Id) { var user = Context.User .GroupJoin( Context.Info, u => u.Id, i => u.UserId, (u, i) => new { u.UserName, i.Single(d => d.Field == "Name"), i.Single(d => d.Field == "Age"), ... }); } |


浙公网安备 33010602011771号