zoukankan      html  css  js  c++  java
  • 【Normal Form】数据库表结构设计所遵从的范式

    数据库设计是件严肃、关键的事儿,一毕业,加入一个大型的行业项目,那儿的前辈资深工程师,就给我灌输数据库如何关键、神圣、深不可测的观念,所以,我一直怀着崇拜的眼神。

    几年前,项目经理把一个小项目的数据库设计工作交给我,我除了花费晚上和周末去完成。后来,更由于第一次负责整个系统的数据库设计,更请教了以前公司的架构师哥们,帮我把把关,看自己有哪些木有想到的。

    后来,将设计方案通过了评审,甚是高兴,毕竟自己第一次设计一个系统的表结构,尽管,是一个小系统。

    那么,有了几次数据库表结构设计经验,如何描述你设计表所遵循的原则呢?这时候,回归到大学课本,就是范式(Normal Form)。

    第一范式:原子性,不可再分

    原子性,即,字段应该是不可再分的。

    是否为原子性

    如,一个系统的地址用于邮寄商品,那么下表的ADDRESS是符合第一范式的。

    ID USER_NAME AGE PHONE ADDRESS
    1 Nick Huang 18 12345678 深圳市罗湖区地王大厦1003室

    而如何判断是否原子性,这需要根据实际的业务判断。

    比如一些系统仅根据地址作送货服务的,则使用上述的结构即满足第一范式;而某些系统,地址除了用于送货,还需要对用户所在地区分布做长期的统计,为了统计方便,上面的ADDRESS设计就不符合原子性了,也许应该为:

    ID USER_NAME AGE PHONE PROVINCE CITY ADDRESS
    1 Nick Huang 10 12345678 广东省 深圳市 地王大厦1003室

    典型的例子:多个信息用分隔符拼接记录

    还有其他一些典型的不符合原子性的,就是将多个数据放在一个字段中了。

    如Phone字段:

    ID USER_NAME AGE PHONE
    1 Nick Huang 10 23658745,25654150

    还有这种情况,如EXT_FIELDS字段:

    ID USER_NAME AGE PHONE ADDRESS EXT_FIELDS
    1 Nick Huang 10 12345678 深圳市XXX <DATA><JOB>Programmer</JOB><PASSPORT>12345678</PASSPORT></DATA>

    第二范式:非主键必须完全依赖于主键,而不能只依赖于主键的一部分

    非主键必须完全依赖于主键,而不能只依赖于主键的一部分(联合主键)

    不符合此特性的示例

    博文《权限管理系统概要设计》有一系列用户权限的表,如果以此为例子,将其中的表结构设计为如下,则不符合第二范式:

    USER_ID、ROLE_ID为主键,描述用户和角色的关联关系;STATUS描述这个关联关系是生效还是失效。

    可以看出,STATUS是描述这段关联的,是依赖USER_ID、ROLE_ID的,即完全依赖于主键。

    而USER_NAME是用户名称,它只依赖于USER_ID,即只依赖于主键的一部分。USER_NAME字段的设置不符合第二范式。

    如果有一天,用户的名称需要修改,那么就要修改与此用户相关的每一笔关联的数据。

    第三范式:非主键必须直接依赖于主键,而不是传递依赖或间接依赖

    非主键必须直接依赖于主键,而不是传递依赖或间接依赖。

    不符合此特性的示例

    博文《权限管理系统概要设计》有一系列用户权限的表,如果以此为例子,将其中的表结构设计为如下,则不符合第三范式:

    此为角色表,ID为角色ID,NAME为角色名称,STATUS为此角色是否生效,SYSTEM_ID为此角色所属的系统ID,SYSTEM_NAME为此角色所属的系统的名称。

    可以看出SYSTEM_NAME为传递依赖,在角色表中SYSTEM_ID依赖与ID,而SYSTEM_NAME有依赖与SYSTEM_ID。SYSTEM_NAME字段的设置不符合第三范式。

    后话

    是不是数据库设计一定得严格遵守3范式呢?

    这不一定,要视具体情况,实际上,常见许多情况故意设置冗余字段使系统查询更高效、更方便。

    参考的优秀文章

    数据库(第一范式,第二范式,第三范式)

  • 相关阅读:
    ExtJs学习笔记之ComboBox组件
    ExtJs学习笔记之学习小结LoginDemo
    ExtJs学习笔记之Button组件
    ExtJs学习笔记之TextField
    WAF指纹识别和XSS过滤器绕过技巧
    python中的迭代与递归
    使用Python对文档单词进行计数
    Python正则表达式使用实例
    Python十六进制与字符串的转换
    数组名a,数组名取地址&a,数组首地址&a[0],数组指针*p
  • 原文地址:https://www.cnblogs.com/nick-huang/p/4361056.html
Copyright © 2011-2022 走看看