关于数据库设计的重要性
关于数据库设计的重要性
web开发是面向数据集的开发,我们开发人员对现实世界的抽象的一步就是建立表(或者你可以理解成类),而且在关系型数据的设计中,我是非常看重三范式!!!非常!!!,因为table是一切的源头,如果你的表设计不合理;那么你上层的代码也跟着错;而且后面的设计,将会错的各种离谱,我已经不想吐槽!!
这里,我会屡屡序序的完整这篇文章,讲讲个人对三范式的理解和它重要性;我们先提概念,再结合实际来一步一步的分析;
我先从简单的,一步一步的深入;
总的来说分成两部分!
1.实体的设计
2.实体关系的设计
实体设计原则一:原子性,不可分割性
比如product 中有一字段是价格,而我们的价格可以继续再分(进价 卖价);如果设计为一个字段,将带来一定的模糊性
实体设计原则二:完全依赖主键,不存在部分依赖(可以理解成一个表只存一个实体相关的信息)
sId,name,classNo,className
这样的设计,明显不合理,应该拆分成两个表
实体设计原则三:不存在非主键属性之间的依赖(就是字段与字段之间不存在依赖性)
这一点是对第二原则的进一步补充;如:jobName 和 jobDescript 两个字段就有一定的依赖性;如果存在这样的依赖,就会导致jobDescript的重复出现;
其实,跟人觉得这个问题都不大~
2.实体关系的设计
1.一对一
2.一对多
3. 多对多
关系的设计体现在我们的设计的合理性和约束的合理性;
问题一,关系混乱,将jion后的数据数据,记录在一张表中!
如:
张三 语文 60
张三 数学 70
张三 外语 80
这个数据应该是,姓名表,课程表,成绩表,三张表jion之后的数据!!而不是所谓的“”成绩表“”,如果就这样设计,我们看看带来的问题;
1.Create
一数据重复:
1.姓名重复:明显看出如果,张三选了十门课程,那么张三会重复十次!
2.课程重复:明显看出如果,语文背全班60个同学选择,那么结果就是语文会重复60次!
2.修改
还有一种关系如:产品类别和产品之间的关系建立(应该是一对多,应该没问题吧);
假设,我们这里用codefirst 方式来模拟建表的过程;
比如,一个类别有多个产品;表设计如下!!!
/// <summary> /// 类别信息; /// </summary> public class Category { public string Id { get; set; } public string CategoryName { get; set; } public string Remark { get; set; } public string ProuductIds { get; set; } }
产品表
/// <summary> /// 产品表 /// </summary> public class Product { public string Id { get; set; } public string Name { get; set; } }
类别和产品的关系我们通过ProuductIds 关联起来,中间用逗号分开!!也就想像这样(1,2,3,4,5)
然后,我们来看存在的问题;
1.Create
Insert into Category(CategoryName,Remark,ProductIds) values ('nicke鞋','鞋','1,2,3,4,5,6') --假设有五种产品;
问题,如果6 这个产品不存在,导致的结果就是:添加不存在的产品!!!
2.Update
更新到简单,我们可以直接覆盖原来的数据;把ProductIds=(‘1,2,3,4,5,6’) 跟新为 ProductIds=(‘1,2,3,7’)
问题:由于缺乏数据一致性的约束,我们同样可能将不存在的数据(产品)添加进去
3.Delete
如果是全部删除,那还没什么问题,直接清空,ProductIds=(‘1,2,3,4,5,6’) 跟新为 ProductIds=(‘’)
如果只是更新部(删除)部分呢,同样,由于缺乏数据一致性的约束,导致,我们更新一些,不存在的产品;
正确的设计应该是,在Product中建立外键关联;如下
/// <summary> /// 产品类别信息; /// </summary> public class Category { public string Id { get; set; } public string CategoryName { get; set; } public string Remark { get; set; } } /// <summary> /// 产品表 /// </summary> public class Product { public string Id { get; set; } public string Name { get; set; } public string CategoryId { get; set; } }
上面的设计,其实体现的是主外键的约束的重要性;如果少了约束可能导致的问题
1.Create
添加一个不存在的数据!(如在添加产品是,你将该产品附属到一个不存在的类别上!)
2.Detele
删除一个有依赖项目数据!如(某个角色下还有用户,你就将用户个删除了!)
3.Update
更新得不到通知!
数据冗余问题一!
在实际的开发中,我们可能常常会获取产品名称的同时获取他的额产品类别名称;有些同学为了获取方便(避免join获取数据)设计成这样!
/// <summary> /// 产品表 /// </summary> public class Product { public string Id { get; set; } public string Name { get; set; } public string CategoryId { get; set; } /// <summary> /// 产品名称 /// </summary> public string CategoryName { get; set; } }
在添加的是偶,添加产品信息的同时 保存 CategoryId的同时,保存CategoryName;!!!
这样在查询的时候,确实方便了不少,因为不用join去获取类别名称,但是问题来了;!!
如果Category 表中CategoryName改变了,你是不是要改变Product表中的CategoryName呢?
所以建议不要去冗余那个CategoryName!因为category中的数据更新,product 中的数据得不到”更新通知”
这样就无法维持数据的一直性!!!!!
数据冗余问题二!
还有一些关于数据不合理,然后导致数据冗余,居然有些开发者,说为了提高查询效率,避免jion;真的醉了;
我们来看实际的场景;在关系型数据库中,主外键的约束带来了数据一致性的维护!同时也带了一个查询的问题;
那就是我们的join的代价,(这个也是我们nosql出现的重要原因);这里要强调的是“千万别装逼!”,不要很小的数据,也在哪里提什么join的代价!shit!
noslq的应用场景;
1.对数据的一致性要求不高;
2.外键相关联的表的数据表的变动非常小,
3.数据量特别,根本不敢去join!
如:
博客,和评论;和评论的信息,如果每次去取数据都通过join的话,那么开销是非常大的;而且评论一旦定了之后,变的几率比较小;
我们就可以利用MongoDB,json方式,存储这种结构化的数据!
{ "type": "post", "name": "Raven's Map/Reduce functionality", "blog_id": 1342, "post_id": 29293921, "tags": ["raven", "nosql"], "post_content": "<p>...</p>", "comments": [ { "source_ip": '124.2.21.2', "author": "martin", "text": "..." }] }
数据库的设计了体现了我们队现实世界的抽象过程!那么往一一层走就是我们oop设计的能力了,也就是我们c#的写的能力了!