关系数据库的几种设计范式介绍

来源:未知 责任编辑:智问网络 发表时间:2013-11-12 17:22 点击:
1 第一范式(1NF)
 
      在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
 
      所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。例如,对于图3-2 中的员工信息表,不能将员工信息都放在一列中显示,也不能将其中的两列或多列在一列中显示;员工信息表的每一行只表示一个员工的信息,一个员工的信息在表中只出现一次。简而言之,第一范式就是无重复的列。
 
2 第二范式(2NF)
 
      第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。如图3-2 员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。
 
      第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。
 
3 第三范式(3NF)
 
      满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在图3-2的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。简而言之,第三范式就是属性不依赖于其它非主属性。
 
数据库设计三大范式应用实例剖析
 
      数据库的设计范式是数据库设计所需要满足的规范,满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。反之则是乱七八糟,不仅给数据库的编程人员制造麻烦,而且面目可憎,可能存储了大量不需要的冗余信息。
 
   设计范式是不是很难懂呢?非也,大学教材上给我们一堆数学公式我们当然看不懂,也记不住。所以我们很多人就根本不按照范式来设计数据库。
 
   实质上,设计范式用很形象、很简洁的话语就能说清楚,道明白。本文将对范式进行通俗地说明,并以笔者曾经设计的一个简单论坛的数据库为例来讲解怎样将这些范式应用于实际工程。
 
   范式说明
 
   第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。
 
   例如,如下的数据库表是符合第一范式的:
 
字段1  字段2  字段3  字段4 
 
               
 
   而这样的数据库表是不符合第一范式的:
 
字段1  字段2  字段3  字段4 
 
        字段3.1  字段3.2     
 
 
 
   很显然,在当前的任何关系数据库管理系统(DBMS)中,傻瓜也不可能做出不符合第一范式的数据库,因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此,你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。
 
   第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。
 
   假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分),关键字为组合关键字(学号, 课程名称),因为存在如下决定关系:
 
  (学号, 课程名称) →(姓名, 年龄, 成绩, 学分)
 
   这个数据库表不满足第二范式,因为存在如下决定关系:
 
  (课程名称) →(学分)
 
  (学号) →(姓名, 年龄)
 
   即存在组合关键字中的字段决定非关键字的情况。
 
   由于不符合2NF,这个选课关系表会存在如下问题:
 
  (1) 数据冗余:
 
   同一门课程由n个学生选修,"学分"就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。
 
  (2) 更新异常:
 
   若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况。
 
  (3) 插入异常:
 
   假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有"学号"关键字,课程名称和学分也无法记录入数据库。
 
  (4) 删除异常:
 
   假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。
 
   把选课关系表SelectCourse改为如下三个表:
 
   学生:Student(学号, 姓名, 年龄);
 
   课程:Course(课程名称, 学分);
 
   选课关系:SelectCourse(学号, 课程名称, 成绩)。
 
   这样的数据库表是符合第二范式的, 消除了数据冗余、更新异常、插入异常和删除异常。
 
   另外,所有单关键字的数据库表都符合第二范式,因为不可能存在组合关键字。
 
   第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如果存在"A →B →C"的决定关系,则C传递函数依赖于A。因此,满足第三范式的数据库表应该不存在如下依赖关系:
 
   关键字段 → 非关键字段x → 非关键字段y
 
   假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),关键字为单一关键字"学号",因为存在如下决定关系:
 
  (学号) →(姓名, 年龄, 所在学院, 学院地点, 学院电话)
 
   这个数据库是符合2NF的,但是不符合3NF,因为存在如下决定关系:
 
  (学号) →(所在学院) →(学院地点, 学院电话)
 
   即存在非关键字段"学院地点"、"学院电话"对关键字段"学号"的传递函数依赖。
 
   它也会存在数据冗余、更新异常、插入异常和删除异常的情况,读者可自行分析得知。
 
   把学生关系表分为如下两个表:
 
   学生:(学号, 姓名, 年龄, 所在学院);
 
   学院:(学院, 地点, 电话)。
 
   这样的数据库表是符合第三范式的,消除了数据冗余、更新异常、插入异常和删除异常。
 
   鲍依斯-科得范式(BCNF):在第三范式的基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。
 
   假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:
 
  (仓库ID, 存储物品ID) →(管理员ID, 数量)
 
  (管理员ID, 存储物品ID) →(仓库ID, 数量)
 
   所以,(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:
 
  (仓库ID) →(管理员ID)
 
  (管理员ID) →(仓库ID)
 
   即存在关键字段决定关键字段的情况,所以其不符合BCNF范式。它会出现如下异常情况:
 
  (1) 删除异常:
 
   当仓库被清空后,所有"存储物品ID"和"数量"信息被删除的同时,"仓库ID"和"管理员ID"信息也被删除了。
 
  (2) 插入异常:
 
   当仓库没有存储任何物品时,无法给仓库分配管理员。
 
  (3) 更新异常:
 
   如果仓库换了管理员,则表中所有行的管理员ID都要修改。
 
   把仓库管理关系表分解为二个关系表:
 
   仓库管理:StorehouseManage(仓库ID, 管理员ID);
 
   仓库:Storehouse(仓库ID, 存储物品ID, 数量)。
 
   这样的数据库表是符合BCNF范式的,消除了删除异常、插入异常和更新异常。
 
   范式应用
 
   我们来逐步搞定一个论坛的数据库,有如下信息:
 
   (1) 用户:用户名,email,主页,电话,联系地址
 
   (2) 帖子:发帖标题,发帖内容,回复标题,回复内容
 
   第一次我们将数据库设计为仅仅存在表:
 
用户名  email  主页  电话  联系地址  发帖标题  发帖内容  回复标题  回复内容 
 
   这个数据库表符合第一范式,但是没有任何一组候选关键字能决定数据库表的整行,唯一的关键字段用户名也不能完全决定整个元组。我们需要增加"发帖ID"、"回复ID"字段,即将表修改为:
 
用户名  email  主页  电话  联系地址  发帖ID  发帖标题  发帖内容  回复ID  回复标题  回复内容 
 
   这样数据表中的关键字(用户名,发帖ID,回复ID)能决定整行:
 
  (用户名,发帖ID,回复ID) →(email,主页,电话,联系地址,发帖标题,发帖内容,回复标题,回复内容)
 
   但是,这样的设计不符合第二范式,因为存在如下决定关系:
 
  (用户名) →(email,主页,电话,联系地址)
 
  (发帖ID) →(发帖标题,发帖内容)
 
  (回复ID) →(回复标题,回复内容)
 
   即非关键字段部分函数依赖于候选关键字段,很明显,这个设计会导致大量的数据冗余和操作异常。
 
   我们将数据库表分解为(带下划线的为关键字):
 
   (1) 用户信息:用户名,email,主页,电话,联系地址
 
   (2) 帖子信息:发帖ID,标题,内容
 
   (3) 回复信息:回复ID,标题,内容
 
   (4) 发贴:用户名,发帖ID
 
   (5) 回复:发帖ID,回复ID
 
   这样的设计是满足第1、2、3范式和BCNF范式要求的,但是这样的设计是不是最好的呢?
 
   不一定。
 
   观察可知,第4项"发帖"中的"用户名"和"发帖ID"之间是1:N的关系,因此我们可以把"发帖"合并到第2项的"帖子信息"中;第5项"回复"中的"发帖ID"和"回复ID"之间也是1:N的关系,因此我们可以把"回复"合并到第3项的"回复信息"中。这样可以一定量地减少数据冗余,新的设计为:
 
   (1) 用户信息:用户名,email,主页,电话,联系地址
 
   (2) 帖子信息:用户名,发帖ID,标题,内容
 
   (3) 回复信息:发帖ID,回复ID,标题,内容
 
   数据库表1显然满足所有范式的要求;
 
   数据库表2中存在非关键字段"标题"、"内容"对关键字段"发帖ID"的部分函数依赖,即不满足第二范式的要求,但是这一设计并不会导致数据冗余和操作异常;
 
   数据库表3中也存在非关键字段"标题"、"内容"对关键字段"回复ID"的部分函数依赖,也不满足第二范式的要求,但是与数据库表2相似,这一设计也不会导致数据冗余和操作异常。
 
   由此可以看出,并不一定要强行满足范式的要求,对于1:N关系,当1的一边合并到N的那边后,N的那边就不再满足第二范式了,但是这种设计反而比较好!
 
   对于M:N的关系,不能将M一边或N一边合并到另一边去,这样会导致不符合范式要求,同时导致操作异常和数据冗余。
 
对于1:1的关系,我们可以将左边的1或者右边的1合并到另一边去,设计导致不符合范式要求,但是并不会导致操作异常和数据冗余。
 
   结论
 
   满足范式要求的数据库设计是结构清晰的,同时可避免数据冗余和操作异常。这并意味着不符合范式要求的设计一定是错误的,在数据库表中存在1:1或1:N关系这种较特殊的情况下,合并导致的不符合范式要求反而是合理的。
 
   在我们设计数据库的时候,一定要时刻考虑范式的要求。
 
一、必要性
 
  随着近年来数据库技术的深入发展,以Unix平台为代表的Informix Dynamic Server和以NT平台为代表的MS SQL Server得到了广泛的应用。在一个公共的环境中,存在大量的用户操作,有数据库管理员,主要做数据管理维护工作,也有普通用户,做一定授权下的数据修改和数据查询。我们知道,每个数据库服务器上可建立多个不同类别的数据库,而每个数据库中也可以生成多个存储过程、表、视图等。如何保证数据的安全可靠,防止非法存取所造成的破坏和数据泄露,如何进行权限的划分和设置,这是安全管理的重点,也是数据库可靠运行的保证。本文以Informix Dynamic Server为例做详细说明。
 
  二、权限的划分
 
  Informix Dynamic Server使用了三级权限来保证数据的安全性,它们分别是数据库级权限、表级权限和字段级权限,具体为:
 
  1.数据库级权限
 
  包括Connect、Resource、DBA三种类别,其中:
 
  Connect:最低级,仅允许用户访问数据库中的表和索引,但不能创建和删除它们;
 
  Resource: 建立在Connect之上,允许用户在数据库中创建、删除表和索引;
 
  DBA:即数据库管理员,拥有数据库管理的全部权限,包括访问数据库表、创建和删除索引、修改表结构、授予数据库权限给其他用户等。
 
  2.表/字段(视图)级权限
 
  指允许进行何种具体操作,主要包括:
 
  Select: 从表或字段中检索信息;
 
  Update: 修改指定字段的值;
 
  Insert: 向数据库表中添加记录;
 
  Delete: 从数据库表中删除记录;
 
  Index: 为一个数据库表创建索引;
 
  Alter: 增加、删除数据库表中的字段,或修改字段的数据类型;
 
  All: 以上所有权限。
 
  三、权限的设置
 
  Informix Dynamic Server通过一系列SQL控制语句来实施对用户权限的设置,使得不同的用户只能在各自限定的范围内存取数据。以下命令格式中Grant表示授予权限,Revoke表示撤消权限,User-List指用户名列表,多个用户以逗号(,)分隔,对大多数数据库系统而言,PUBLIC代表所有用户。
 
  1.对于数据库,其格式为:
 
  Grant { DBA  Resource  Connect } to { PUBLIC  User-List };
 
  Revoke { DBA  Resource  Connect } from { PUBLIC  User-List }
 
  缺省情况下,建立数据库的用户就是数据库管理员(DBA),除其本身和Informix用户外,其它用户不对该数据库拥有任何权限,因此也就不能进行任何形式的访问。数据库管理员可根据其他用户的业务分工、操作范围授予或撤消DBA、Resource、Connect三种不同的权限。
 
  2.对于表及视图,其格式为:
 
  Grant TAB-PRI on [ tab_name  view_name ] to { PUBLIC  User-List };
 
  Revoke TAB-PRI on [ tab_name  view_name ] from { PUBLIC  User-List }
 
  其中TAB_PRI表示select、update、delete等操作权限,tab_name、view_name分别代表数据库表名和视图名。
 
  缺省情况下,新建的数据库表和视图对能够访问该数据库的用户赋予了除alter外的所有权限,有时这是比较危险的,比如对普通查询用户,应该有针对性地对权限重新定义。此外,对一些重要的表或视图,为防止敏感信息泄露,也应该重新授权。具体做法是:先用Revoke命令撤消原来所有的权限,再用Grant授予新的权限。
 
  3.对于字段:
 
  字段级权限的授予和撤消同表级的命令方式基本一致,所不同的仅在于必须把赋予权限的字段名列在操作权限如select、insert、update等之后,通过这样细化可以实施更有效的数据保护。
 
  4.对于存储过程:
 
  存储过程由SQL语句编写,存放于数据库中,常与触发器配合,可以对数据进行批量处理,使用非常方便。但如果授权不严格,将导致非法修改现有数据。其权限设置格式为:
 
  Grant Execute on proc_name to { PUBLIC  User-List };
 
  Revoke Execute on proc_name from { PUBLIC  User-List }
 
  其中proc_name表示存储过程名。
 
  四、角色(role)的使用
 
  
 
  在数据库用户的管理中,我们可以根据用户对数据库数据的需要情况把用户分为几组,每一组用户可以作为一个"角色",每个用户就是角色的成员。通过使用角色,数据库系统更容易进行安全性管理,因为一旦某个用户属于某一个角色,对权限的授予和撤消只需针对角色便可。具体使用方法为:
 
  1.创建角色:
 
  Create Role role_name1
 
  其中role_name1表示角色名。
 
  2.划分用户角色:
 
  即将相关用户加入到角色中使之成为角色的成员。
 
  Grant role_name1 to { User-List  Role_List }
 
  其中Role_List表示角色列表,因为一个角色可以是另外一个或一组角色的成员。
 
  3.授权角色权限:
 
  同授权用户权限的方法相同,但只能对表级和字段级权限有效,不能授予数据库级权限给一个角色。
 
  4.激活角色:
 
  执行以下语句,使以上定义的角色成为可用状态:
 
  Set Role role_name1
 
  五、结束语
 
  以Internet技术为代表的网络业务的迅猛增长为数据库应用开辟了新的发展空间,同时也对数据库的安全性管理提出了更高的要求,网络的开放性导致非法存取常有发生,因而深刻领会和理解数据库权限的具体设置方法,结合自身实际应用,制定出一套完整的安全保护策略具有重要意义。Informix Dynamic Server对以上控制语句的使用除角色外,严格执行SQL ANSI 标准,因此对建立在NT平台上的MS SQL Server同样有效
    发表评论
    请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
    用户名: 验证码:点击我更换图片
    最新评论 更多>>

    推荐热点

    • Request.ServerVariables 参数大全
    • 执行全文索引时出现权限不足的解决方法
    • 导入excel文件处理流程节点的解决方案
    • 查看sql修改痕迹(SQL Change Tracking on Table)
    • App数据层设计及云存储使用指南
    • PostgreSQL启动过程中的那些事三:加载GUC参数
    • MongoDB安装为Windows服务方法与注意事项
    • Percolator与分布式事务思考(二)
    • 写给MongoDB开发者的50条建议Tip1
    网站首页 - 友情链接 - 网站地图 - TAG标签 - RSS订阅 - 内容搜索
    Copyright © 2008-2015 计算机技术学习交流网. 版权所有

    豫ICP备11007008号-1