数据库设计Step by Step (7)——概念数据建模

阅读原文 转自博客园 知行思新

引言:在前两篇博文(数据库设计 Step by Step (5)数据库设计 Step by Step (6) —— 提取业务规则)中,我们进行了数据库需求分析,着重讨论了两个主题:1.理解用户需求;2.提取业务规则。当需求分析完成后,我们就要进入到概念数据建模环节。本篇文章将使用之前介绍过的“基本实体关系模型构件”和“高级实体关系模型构件”作为建模的基本元素,大家可以回顾数据库设计 Step by Step (3)数据库设计 Step by Step (4)中的模型构件及语义。

逻辑数据库设计有多种实现方式,包括:自顶至底,自底至顶以及混合方式。传统数据库设计是一个自底至顶的过程,从分析需求中的单个数据元素开始,把相关多个数据元素组合在一起转化为数据库中的表。这种方式较难应对复杂的大型数据库设计,这就需要结合自顶至底的设计方式。

使用ER模型进行概念数据建模方便了项目团队内部及与最终用户之间的交流与沟通。ER建模的高效性还体现在它是一种自顶至底的设计方法。一个数据库中的实体数量比数据元素少很多,因为大部分数据元素表示的是属性。辨别实体并关注实体之间的关系能大大减少需要分析的对象数量。

概念数据建模连接了两端,一端是需求分析,其能辅助捕获需求中的实体及之间的关系,便于人们的交流。另一端是关系型数据库,模型可以很容易的转化为范式化或接近范式化的SQL表。

概念数据建模步骤

让我们进一步仔细观察应在需求分析和概念设计阶段定义的基本数据元素和关系。一般需求分析与概念设计是同步完成的。

使用ER模型进行概念设计的步骤包括:

  1. 辨识实体与属性
  2. 识别泛化层次结构
  3. 定义关系

下面我们对这三个步骤一一进行讨论。

辨识实体与属性

实体和属性的概念及ER构图都很简单,但要在需求中区分实体和属性不是一件易事。例如:需求描述中有句话,“项目地址位于某个城市”。这句话中的城市是一个实体还是一个属性呢?又如:每一名员工有一份简历。这里的简历是一个实体还是一个属性呢?

辨别实体与属性可参考如下准则:

  1. 实体应包含描述性信息
  2. 多值属性应作为实体来处理
  3. 属性应附着在其直接描述的实体上

这些准则能引导开发人员得到符合范式的关系数据库设计。

如何理解上述的三条准则呢?

实体内容:实体应包含描述信息。如果一个数据元素有描述型信息,该数据元素应被识别为实体。如果一个数据元素只有一个标识名,则其应被识别为属性。以前面的“城市”为例,如果对于“城市”有一些如所属国家、人口等描述信息,则“城市”应被识别为一个实体。如果需求中的“城市”只表示一个城市名,则把“城市”作为属性附属与其他实体,如附属Project实体。这一准则的例外是当值的标识是可枚举的有限集时,应作为实体来处理。例如把系统中有效的国家集合定义为实体。在现实世界中作为实体看待的数据元素有:Employee,Task,Project,Department,Customer等。

多值属性:把多值属性作为实体。如果一个实例的某个描述符包含多个对应值,则即使该描述符没有自己的描述信息也应作为实体进行建模。例如:一个人会有许多爱好,如:看电影、打游戏、大篮球等。爱好对于一个人来说就是多值属性,则爱好应作为实体来看待。

属性依附:把属性附加在其最直接描述的实体上。例如:“office-building-name”作为“Department”属性比作为“Employee”的属性合适。识别实体与属性,并把属性附加到实体中是一个循环迭代的过程。

识别泛化层次

如果实体之间有泛化层次关系,则把标识符和公共的描述符(属性)放在超类实体中,把相同的标识符和特有的描述符放在子类实体中。举例来说,在ER模型中有5个实体,分别是Employee、Manager、Engineer、Technician、Secretary。其中Employee可以作为Manager、Engineer、Technician、Secretary的超类实体。我们可以把标识符empno,公共描述符empname、address、date-of-birth放在超类实体中。子类实体Manager中放empno,特有描述符jobtitle。Engineer实体中放empno,特有描述符jobtitle,highest-degree等。

定义关系

在识别实体和属性之后我们可以处理代表实体之间联系的数据元素即关系。关系在需求描述中一般是一些动词如:works-in、works-for、purchases、drives,这些动词联系了不同的实体。

对于任何关系,需要明确以下几个方面。

  1. 关系的度(二元、三元等);
  2. 关系的连通数(一对一、一对多等);
  3. 关系是强制的还是可选的;
  4. 关系本身有些什么属性。

注:关系的这些概念可参看数据库设计 Step by Step (3),这里不再赘述。

冗余关系

仔细分析冗余的关系。描述同一概念的两个或多个关系被认为是冗余的。当把ER模型转化为关系数据库中的表时,冗余的关系可能造成非范式化的表。需要注意的是两个实体间允许两个或更多关系的存在,只要这些关系具有不同的含义。在这种情况下这些关系不是冗余的。

举例来说,如下图1中Employee生活的City与该Employee所属的Professional-association的所在City可以不同(两种含义),故关系lives-in非冗余。

(图1  非冗余关系)

三元关系

非常小心的定义三元关系,只有当使用多个二元关系也无法充分描述多个实体间的语义时,我们才会定义三元关系。以Technician、Project、Notebook为例。

例1:如果 一个Technician只做一个Project,一个Project只有一个Technician,每个Project会被独立记录在一本Notebook中。

(图3 例1二元关系图)

例2:如果一个Technician能同时做多个Project,一个Project可以有多个Technician同时参与,每个Project有一本Notebook(多个做同一个Project的Technician共用一本Notebook)

(图4 例2二元关系图)

例3:如果一个Technician能同时做多个Project,一个Project可以有多个Technician同时参与,一个Technician在一个Project中使用独立的一本Notebook。

(图5 例3三元关系图)

注:三元关系的语义分析可参看数据库设计 Step by Step (4),这里不再赘述。

我们假设要为一家工程项目公司设计一个数据库来跟踪所有的全职员工,包括员工被分配的项目,所拥有的技能,所在的部门和事业部,所属于的专业协会,被分配的电脑。

单个视图的ER建模

通过需求收集与分析过程,我们获得了数据库的3个视图。

第一个视图是人力资源管理视图。每一个员工属于一个部门。事业部是公司的基本单元,每个事业部包含多个部门。每一个部门和事业部都有一个经理,我们需要跟踪每一个经理。这一视图的ER模型如图6所示。

(图6  人力资源关系视图)

第二个视图定义了每个员工的头衔,如工程师、技术员、秘书、经理等。工程师一般属于某个专业协会,并可能被分配一台工作站。秘书和经理会被分配台式电脑。公司会储备一些台式电脑和工作站,以分配给新员工或当员工的电脑送修时进行出借。员工之间可能有夫妻关系,这也需要在系统中进行跟踪,以防止夫妻员工之间有直接领导关系。这一视图的ER模型如图7所示。

(图7  员工头衔及电脑分配视图)

第三个视图如图8所示,包含员工(工程师、技术员)分配项目的信息。员工可以同时参与多个项目,每一个项目可以在不同的地方(城市)设有总部。但一个员工在指定的地点只能做当地的一个项目。员工在不同的项目中可以选用不同的技能。

(图8  项目分配及技能使用视图)

全局ER图

对三个视图的简单集成可得到全局ER图,如图9所示,它是构造范式化表的基础。全局ER图中的每一个关系都是基于企业中实际数据的一个可验证断言。对这些断言进行分析导出了从ER图到关系数据库表的转化。

(图9  全局ER图)

从全局ER图中可以看到二元、三元和二元回归关系;可选和强制存在性关系;泛化的分解约束。图9中三元关系“skill-used”和“assigned-to”是必须的,因为使用二元关系无法描述相同的语义。

可选存在性的使用,Employee与Division或与Department之间是基于常识:大多数Employee不会是Division或Department的经理。另一个可选存在性的例子是desktop或workstation的分配,每一台desktop或workstation未必都会分配给一个人。总而言之,在把ER模型转化为SQL表之前,所有的关系、可选约束、泛化层次都需要与系统的最终用户进行确认。

总结来说,在关系数据库设计中应用ER模型会带来如下好处

1. 使用ER模型可帮助项目成员专注在讨论实体之间的重要关系上,而不受其他细节的干扰。

2. ER模型把大量复杂的语言描述转化为精简的、易理解的图形化描述。

3. 对原始ER模型的扩展,如可选和强制存在性关系,泛化关系等加强了ER模型对现实语义的描述能力。

4. 从ER模型转化为SQL表有完整的规则,且易于使用。

实体关系(ER)模型参考资料

1. 基本实体关系模型构件——实体、关系、属性、关系的度、关系的连通数、关系的属性、关系中实体的存在性(http://www.cnblogs.com/DBFocus/archive/2011/04/24/2026142.html

2. 高级实体关系模型构件——泛化、聚合、三元关系(http://www.cnblogs.com/DBFocus/archive/2011/05/07/2039674.html

下一篇:数据库设计 Step by Step (8)——视图集成

数据库设计 Step by Step (6) —— 提取业务规则

阅读原文 转自博客园 知行思新

引言:数据库设计 Step by Step (5)中我们通过多种方法来理解客户的需求并撰写了需求文档。本文我们将回答三个问题。1. 为什么业务规则非常重要。2. 怎样识别业务规则。3. 如何修改关系模型并隔离出业务规则。

什么是业务规则

业务规则描述了业务过程中重要的且值得记录的对象、关系和活动。其中包括业务操作中的流程、规范与策略。业务规则保证了业务能满足其目标和义务。

生活中的一些业务规则可能是:

当顾客进入店内,最近的员工须向顾客打招呼说:“欢迎来到×××”。
当客户兑换超过200元的奖券时,柜员须要求查看客户的身份证并复印。当兑换的奖券金额小于25元时,无需客户签字。
早上第一个进办公室的人需要把饮水机加热按钮打开。
本系列我们关注数据库相关的业务规则,一些例子如下:

只有当客户产生第一个订单时才创建该客户的记录。
若一名学生没有选任何一门课程,把他的状态字段设为Inactive。
若销售员在一个月中卖出10套沙发,奖励500元。
一个联系人必须至少有1个电话号码和1个email邮箱。
若一个订单的除税总额超过1000元则能有5%的折扣。
若一个订单的除税总额超过500元则免运费。
员工购买本公司商品能有5%的折扣。
若仓库中某货品的存量低于上月卖出的总量时,则需要进货。
从数据库的视角来看,业务规则是一种约束。简单的约束如:

所有订单必须有一个联系电话。

上述这类简单的规则可以很容易的映射到关系数据库定义中,为字段确定数据类型或设定某字段为必填(不能为NULL)。某些业务规则表达的约束会复杂些,如:

学生每天的上课时间加上项目时间必须在1至14小时之间。

我们可以通过check约束或外键约束来实现这类业务规则。对于一些非常复杂的业务规则,如:

一名教员每周不能少于30小时工作量,其中分为办公时间、实验时间和上课时间。每1小时的课需要0.5小时办公时间进行备课。每1小时实验需1小时办公准备。每周指导学生论文时间不少于2小时。

类似上述的业务规则需要从多个表中收集数据,故在程序代码中实现最为合适。

识别关键业务规则

记录所有的业务规则并对这些规则进行分类能帮助我们更好的在系统中实现业务逻辑

如何实现业务规则不仅与当前的业务逻辑有关,而且与该业务逻辑将来如何变化有关。当一个规则在将来很可能变化时,我们需要使用更复杂但更灵活的方式构建该规则。

举例来说,假设公司只能向当地设有仓库的城市发货,这些城市包括:南京、长沙、西安、广州。业务规则要求订单中的发货城市字段必须为NJ、CS、XA、GZ之一。

我们可以把该规则简单的实现为check约束。但将来公司若在上海有了一个新仓库,就必须从后台数据库端修改该check约束。若公司随后设立更多新仓库或业务规则变化为可以向没有仓库的城市发货,每次我们都需要修改该约束。

考虑另一种实现该业务规则的方法——使用外键。我们创建一张ShippingCities表,其中存放值:NJ、CS、XA、GZ,并让订单表中的发货城市字段外键引用ShippingCities表中的主键。这样订单的发货城市列只能接受ShippingCities中存在的城市。当支持的发货城市增加或减少时,只需要在ShippingCities中插入或删除记录。

两种方式的实现难度差异不大,但前一种方式每次都需要修改数据库结构,后一种只需要修改数据。修改数据不仅更省力而且技术要求也更低。

上述业务规则实现为check约束可能如下:

ShippingCity = ‘NJ’ or ShippingCity = ‘CS’ or ShippingCity = ‘XA’ or ShippingCity = ‘GZ’

上述代码并不复杂,但只有熟悉数据库的程序员从后台才能修改。ShippingCitis表中的数据相对更易于理解,我们可以提供一个界面来让用户自己维护其中的城市。

要识别关键业务规则,我们可以问自己两个问题。

第一、修改规则会有多困难。越是复杂的规则,修改起来越困难且更容易出错。

第二、规则变化的可能性有多大。变化频繁的规则需要额外的设计来更好的应对将来的变化。

需要特别注意的规则(关键业务规则):

枚举值。例如:有效的发货城市,订单状态(Pending, Approved, Shipped)等。
计算参数。例如:对500元以上的订单免运费。这一数值可能在将来会调整为300元或600元。
有效参数。例如:项目组可由2至5人组成。某些项目是否可能由1个人完成或有更多人参与。
交叉记录和交叉表检查。例如:订单中可订购的货品数量不能超过该货品的当前库存数。
可概括性约束。如果可预见到将来需应用一些类似的约束,我们可以考虑把这些约束抽象出来进行管理。例如:某保险公司最近主推保险产品A。对每月能卖出20份A产品的销售人员给予1000元奖金。对于不同的保险产品在不同的时间段可能有不同的推广奖励规则。我们可以把产品名称、编号、销售量、奖金数额、促销时间段提取出来放到一张独立的表中作为计算奖金的参数。
非常复杂的检查有些检查规则非常复杂,把这些规则放到程序代码中实现更为容易和清晰。例如:学生选择理学院的谓词演算课程的前提是已通过理学院的命题演算课程或已通过社科院的逻辑I和II课程或者需要导师的允许。该规则在某些数据库产品中可以通过表级的check约束实现,但放到程序中更易于维护和理解。
一些直接可以在数据库中实现的业务规则:

固定枚举值。例如:性别(男、女),用手习惯(左撇子、右撇子)。
数据类型要求。每个字段具有确定的数据类型是关系型数据库的重要特性之一。滥用通用的数据类型(如string)对性能和数据防错都会带来损害。
必填值。例如:会员必须有手机联系方式。
合理性检查。合理性检查设定的范围基本不会变化。例如:商品的价格大于等于0。
作为软件从业人员不要拒绝或回避变化。世界上唯一不变的就是变化。在收集业务规则时多去了解该规则的业务背景与历史变化历程,而不是逼迫客户保证规则不会变化。尽可能发现所有的业务规则并记录下来。对这些业务规则按变化的可能性和修改难度进行分类,精心设计那些将来可能变化且修改困难的规则。

提取关键业务规则

识别并分类业务规则之后,我们需要在数据库中或数据库外来实现关键业务规则。我们可以参考如下方法:

1. 若规则为检验一组有效值时,把该规则转化为外键约束。先前举例中的有效发货城市就是一个很好的例子。创建ShippingCities表,填入允许的发货城市。然后把Orders表的ShippingCity列设为外键,引用ShippingCities表的主键。

2. 若规则为参数可能变化的计算式时,把这些参数提取到一张表中。例如:一个月内卖出总价超过100万元汽车的销售员能获得500元奖金。把参数100万元和500元提取到一张表中,如果需要甚至可以把一个月的时间段也作为参数提取出来。

我还见过一些软件系统在数据库中有一张通用的参数表。该通用参数表中存放系统需要的各种参数,一些是用于计算、一些是作为检验、另一些决定系统的行为。每一条记录有两个字段:Name和Value。例如需要确定一名销售员能获得多少奖金,我们先要查找Name字段为BonusSales的记录,检查该销售员的销售额是否达到了Value字段的金额,若答案是肯定的再查找Name字段为BonusAward的记录来确定奖金数额。这种设计另有一好处,在程序启动时可以把通用参数表读入内存的某集合中,此后使用参数值时就无需再次连接数据库。

3. 若逻辑或计算规则很复杂时,则提取到代码中进行实现。这里说的代码可以是应用程序端代码,还可以是数据库端存储过程。把规则放到代码中实现的意义在于业务规则与数据库表结构分离了,规则的变化不会影响到数据库表结构。通过结构化编程或面向对象编程来实现复杂的规则更易于维护。

举一个综合性的例子:

一本关于数据库设计的书籍卖出前5000本的版税为5%,5000本至10000本之间的版税为7%,超过10000本后的版税为10%,不同类型书籍的版税可能不同。

上述规则比较复杂且包含多个可能变化的参数,故使用第1、2条方法。我们可以通过存储过程来实现该规则,并把参数隔离到一张参数表中进行维护。创建的参数表为RoyaltyRates,并通过BookId与Books关联(如图1所示)。这样为不同书籍创建新的版税规则就非常容易了。

图1 参数表RoyaltyRates与Books表的关系

多层应用的概念大家都不会陌生。三层应用是最常见的分层方法。对于复杂的业务逻辑一般会在中间层(即业务层)中实现。对于一些基本的验证,如必填信息、数字有效区间等,需要在最上层用户界面以及最底层数据库端进行双重检验。数据库端的约束是阻隔脏数据进入系统的最后一道防线,而用户界面处的检验可以避免错误数据传输到系统后端才被拒绝,节省了系统资源。

注:关于多层应用的更多资料请参见最后的“总结与参考”部分。

Summary

主要内容回顾

1. 业务规则决定了业务如何运行,其涵盖从简单明了的入门打卡到复杂的奖金计算公式。

2. 对于数据库而言,业务规则将影响到数据模型。业务规则确定了每个字段的域(值的类型和范围),是否是必须的,以及该字段要满足的其他条件。

3. 理解业务规则并识别那些需要特别处理的关键规则至关重要。

4. 有些规则简单且基本不变,它们可以很容易的用数据库特性来实现。其他的一些规则可能复杂或时常变化,我们可以把它们从数据库中逻辑的或物理的隔离出来(隔离到参数表、存储过程或业务层中),使它们易于修改。

多层应用参考

1. 谈谈对于企业级系统架构的理解(http://www.cnblogs.com/liping13599168/archive/2011/05/11/2043127.html)

2. Multitier architecture(http://en.wikipedia.org/wiki/Multitier_architecture)

3. Software Architecture, Architects and Architecting(http://www.bredemeyer.com/)

数据库设计Step by Step (7)——概念数据建模

数据库设计 Step by Step (5)——理解用户需求

阅读原文 转自博客园 知行思新

引言:数据库设计 Step by Step (4)中我们讨论了泛化关系、聚合关系、三元关系等高级实体关系模型构件及其语义。从本次讲座开始我将引领大家开始数据库设计之旅,我们将从需求分析开始,途中将经过概念数据建模、多视图集成、ER模型转化为SQL、范式化等过程,最终得到完整、可用的SQL表。

需求分析在数据库生命周期中至关重要,通常也是涉及人员最多的步骤。数据库设计师在这个阶段必须走访最终用户,与他们进行访谈,从而确定用户想在系统中存储什么数据以及想怎样使用这些数据。我们将需求分析分为两个步骤:1.理解用户需求;2.提取业务规则。这次我们先讨论“理解用户需求”。

设计定制化产品——无论是一个数据库、一幅平面广告或一个玩具,都是一个“翻译”的过程。我们需要把浮现在客户脑海中的模糊想法、愿望挖掘出来,并“翻译”成满足他们需求的现实产品。

这个“翻译”过程的第一步就是理解用户的需求。设计最好的订单处理系统对于需要一个电路设计工具的客户来说毫无意义。对客户需求理解的不完全会造成错误或无用的设计与开发,这浪费了你、你的团队还有客户的时间与金钱。(牢记数据库是整个应用开发的根基)

制定一个计划

我们首先制定了一个计划,其中包含挖掘客户需求的一系列步骤。遵循这些步骤能更好地理解客户需求,但在一些项目中我们不需要遵循所有的步骤。举例来说,如果客户是单个人且需求很明确时,我们就不需要进行“搞清谁是谁”与“头脑风暴”了。当客户的数据需要保密时,我们就不能“尝试客户的工作”了。在另一些项目中,调整这些步骤的顺序会更为合适。例如我们可能在去拜访客户和观察他们工作之前先进行“头脑风暴”。

以下按照最普遍的顺序列出了各个步骤。大家根据不同项目的情况可进行灵活调整,目标只有一个就是更好地理解用户需求。

  1. 列出问题清单
  2. 拜访客户
  3. 搞清谁是谁
  4. 挖掘客户大脑
  5. 尝试客户的工作
  6. 学习现有操作
  7. 头脑风暴
  8. 展望未来
  9. 理解客户的质疑
  10. 弄清客户的真正需求
  11. 优先级
  12. 确认你的理解
  13. 撰写需求文档

下面我们将一一解释每一个步骤。

列出问题清单

我们需要思考,向客户问些什么问题可以帮助我们了解项目的目标和范畴(scope)。以下几个方面的问题可以作为起始点。

功能:

以下问题主要涉及系统应完成的功能与目标。

  1. 系统应该做些什么?
  2. 为什么你想建这个系统?
  3. 系统看上去应该是怎样的?
  4. 需要些什么报表?
  5. 用户需要自己定义新报表吗?
  6. 系统的操作者会是谁?

数据需求:

这些问题是为了弄清项目的数据需求。了解需要些什么数据能帮助我们定义数据库表。

  1. 系统界面上需要展现哪些数据?
  2. 这些数据应该由谁来提供?
  3. 这些数据是如何关联的?
  4. 这些工作现在是如何处理的?数据来自哪里?

数据完整性:

这些问题能帮助我们在构建数据库时定义完整性约束。

  1. 哪些数据是必须填写的?(eg: 一条客户记录必须有电话信息吗?)
  2. 数据的有效域是什么?(eg: 电话号码是否有格式规定?地址数据应有多长?)
  3. 系统是否需要根据邮编来检验城市的有效性?
  4. 系统中是否必须在定义了客户之后才能下订单?
  5. 系统要求多高的可用性等级?(系统需要7×24的可用性吗?数据的备份频率要多高?)

安全性:

这些问题能帮助我们了解客户对权限控制与审计方面的需求。

  1. 是否每个用户都需要一个不同的密码?
  2. 是否需要控制不同的用户所能访问的数据?(eg: 销售代表有权限看到客户的信用卡账号,但订单录入专员却不能)
  3. 存储在数据库中的数据是否需要加密?
  4. 谁做了什么操作是否需要记录以便于审计?(eg: 记录销售代表提高客户级别的操作,在需要时可以追溯操作的原因)
  5. 系统中的客户分成几个级别?每个级别的客户有多少?
  6. 是否已有文档记录了用户的工作与权责?

环境:

这些问题能帮助我们了解当前项目将代替其他什么系统或流程,以及项目将与其他哪些系统进行交互。

  1. 当前项目是要代替或升级现有的某系统吗?

•是否有描述现有系统的文档?

•现有系统的哪些功能是需要的?哪些是不需要的?

•现有系统处理些什么数据?这些数据是如何存储的?数据之间是如何关联的?

•是否有关于现有系统数据的文档?

  1. 当前项目必须与其他哪些系统交互?

•项目与其他系统之间如何交互?

•新项目是否需要向现有系统提供数据?如何提供?

•新项目是否需要接收现有系统的数据?如何接收?

•是否有关于其他系统的文档?

  1. 客户的整个业务流程是怎样的?(了解在整个业务流程中当前项目的作用)

拜访客户

了解我们要设计和搭建的系统的最好方式是询问客户。拿着我们在上一步中准备的问题清单安排与客户进行会面。这不会像闲聊那么轻松,向客户了解需求是一个冗长且折磨人的过程。

有时我们的穷追猛问会使客户筋疲力竭感到不快。在这些时候我们必须更为耐心,可以分几次多次会议来了解需求,每次针对几个问题或流程。我们的目标是对我们要解决的问题有一个完全且彻底的理解。

即使我们的项目只是去解决整个业务中的一小部分问题,我们也要试图去了解客户的整体业务流程,这可能会给我们带来意想不到的收获。

搞清谁是谁

意识到不同的客户可能对项目有不同的愿景。我们需要分辨出谁是领导,谁是积极支持者,谁是旁观者,谁是唱反调者。

以下列出了一些常见的客户角色:

  1. 项目发起人——一般是管理层的某位领导,他是项目的最高推动者。他会为项目协调资源,解决项目遇到的一些障碍,但他不会参与到项目每天的事务中。
  2. 项目执行负责人——他对于客户的需求和整个业务最为了解。他是了解用户需求阶段最重要的人,他必须有足够的时间来帮助我们定义项目目标以及回答我们的问题。当别人对某业务环节迟疑不决时,我们需要向他请教。
  3. 客户代表——客户代表是回答我们问题的人,他们也可能成为系统的最终用户。他们可能是某一部分业务的专家,我们需要与多个客户代表进行访谈来了解业务全貌。
  4. 利益相关者——这是项目将影响到的人,其中某些人可能同时也是客户代表。这些人可能对项目也有兴趣,但未必对系统都有发言权。我们在进行系统设计时也需要考虑对这些人的影响(特别是附带损害)。
  5. 唱反调者——这是我们需要关注的一些人。如果唱反调者只是让其他人理性或现实地来看待项目,而并不是彻底反对这个项目的话,他将是我们非常好的资源,他将帮助我们说服其他对项目抱有不切实幻想的客户。而如果唱反调者对整个项目抱有抵触时,我们就必须非常小心,有时需要项目执行负责人出面来协调这些人。

挖掘客户大脑

一旦搞清楚谁是谁之后,我们就要与项目执行负责人讨论客户需要什么。客户希望的解决方案是怎样的,需要包含什么数据,怎样呈现,以及不同数据之间如何关联。

与尽可能多的利益相关者进行交流,我们需要考虑每个人的意见,但心中要牢记项目执行负责人最为理解客户的需求并具有最终决定权。

根据项目的规模,这一过程短则几个小时,长则需要几周才能完成。

尝试客户的工作

观察客户每日的工作能帮助我们更好的理解业务。如果我们能做一会儿客户的工作来了解其中包括的内容那就最好了。

即使我们不能实际尝试客户的工作,一般我们还是可以坐在他们身边近距离观察。告诉客户我们将稍稍降低他们的工作效率并问一些愚蠢且恼人的问题,之后我们就可以开问了。在这个过程中要进行记录,学习尽可能多的东西。有些时候外行者的一些看法可能转化为客户怎么也不会想到的好主意。

学习现有操作

在尝试客户的工作之后,我们还可以看一下是否有其他途径能了解现有流程。通常公司有描述客户角色和职责的操作手册或文档。

寻找客户现在使用的数据存储方式,可能是关系型数据库系统或是电子表格或是纸质的单据等等。了解这些数据是怎样使用的,之间是如何关联的。一般物理数据库之间是通过包含冗余信息来相互关联的,如:客户ID。

头脑风暴

此刻我们已经对客户的业务和需求较为了解了。为了确认没有什么遗漏,我们需要安排头脑风暴。召集项目执行负责人和尽可能多的客户代表与利益相关者,向他们描述前期了解到的需求情况,之后让他们畅所欲言谈谈其中有什么问题或还缺什么。

在这个过程中我们不急于答应或排除任何客户的要求,我们先把客户说到的东西记录下来,并确定这些方面我们已经考虑到了。在正式开发前,我们会与项目执行负责人一起根据项目的规模与交付期限确定需求的优先级。

展望未来

在头脑风暴过程中思考一下将来的需求。问问客户他们的业务在将来是否会变化或他们希望系统将来能包含什么功能。

我们可以把他们的一些想法放入当前的项目中,即使不能也可以使我们知道将来可能会有些什么扩展,在设计数据库时我们能预先留有余地。

理解客户的质疑

一些热心且懂些技术的用户会跑来建议我们如何设计系统,应该创建怎样结构的数据表。我们可能觉得这些建议毫无意义甚至可笑。但在忽视这些建议之前我们应谨慎思考用户提出这些建议或质疑的深层原因是什么。客户比我们更了解业务,他们的建议或质疑中可能蕴含着我们还未了解到的业务变化点或某些特殊业务情况。

弄清客户的真正需求

有时客户并不了解自己的真正需求。他们能看到问题的表象,但未必清楚其根源。我们需要帮助客户寻找到问题的根源并针对问题的源头提出解决方案。

有时客户认为数据库或新系统能神奇般的提高销售,减少成本。事实上一个设计精良的数据库能减少输入差错,提高操作效率,提供数据报表,帮助客户管理数据等等。我们在与客户沟通的过程中需要告诉他们新系统能做些什么,不能做些什么,让客户建立起正确的预期。

优先级

经过先前的步骤,我们已列出一张长长的期望功能列表。其中的某些功能可能不切实际或超出了当前项目的范畴。为了使项目规模可控,我们要与客户一起定义功能的优先级。

一般我们可以把功能分为三个等级。第一优先级是在本期开发中必须包含的功能,没有完成这些功能意味着项目的失败。第二优先级是可以放到下一期开发的功能,当第一优先级的功能完成后,我们可以把第二优先级的部分功能提到当期开发。第三优先级是那些相对不重要或超出项目范畴的功能,我们可以忽略这些功能。

有些情况下优先级是可能转化的。当第一优先级的某功能非常难实现时,我们可以与客户进行沟通,确认该功能是否如此重要,是否能移到第二优先级中以避免影响项目进度。当第二优先级中的某些功能很容易实现,我们可以把该功能调整到第一优先级列表中。但做这些调整之前必须与客户沟通,得到客户的认可。

验证你的理解

梳理我们对业务和需求的理解,并一一与客户进行确认。当客户说“但是”、“除了”、“有时”等词时,我们要特别当心,确认客户只是强调了我们已经知道的东西,而没有出现新的情况。在这个阶段客户可能会想到他们之前没有考虑到的例外情况。

例外情况是数据库设计的大害。在需求分析阶段把例外情况挖掘出来,我们才能在数据库设计时有所准备。例如,我们向客户确认退货流程说:“到这里收货员会输入RMA号并点击完成按钮是吗?”客户可能会说:“嗯…这是大多数情况,但有时没有RMA号,收货员会填入None。”这就是一个客户之前没有告诉我们的重要例外情况,我们必须立刻记录下来。再有一个例子,假设客户使用的纸质订单有配送地址与账单地址两个栏目。我们向客户确认时说:“订单需要有一个配送地址和一个账单地址。”客户打断说:“有时我们需要两个配送地址,因为订单不同部分可能要送到不同的地方。”,并找出一张订单,第二个配送地址被标注在订单的边沿处。这是一个重大例外,在纸上可以很容易的进行标注,但在数据库的一个表单元中增加一个地址是不可能的。只有知道这一例外,我们才能用设计的方法解决这一需求。

撰写需求文档

需求文档描述了我们要构建的系统,该文档也被称为需求规格说明。需求文档要讲清楚我们将构建怎样的系统,该系统会完成什么工作,包含哪些功能点,并描述客户如何使用该系统来解决他们的问题。需求文档明确了项目将完成的功能,这也避免了系统交付时出现争执的情况。

需求文档中应定义可交付成果,即里程碑。里程碑是可直观展现并能验证的中间成果。客户通过里程碑能衡量项目的进度。在需求文档中还需定义最终交付成果,这也是确定项目是否完成的标准。

用例图是一种非常好的需求分析工具,可以作为需求文档的一部分。用例图的最主要功能就是用来表达系统的功能性需求或行为。用例图从业务角度上体现谁来使用系统、用户希望系统提供什么样的服务,以及用户需要为系统提供的服务,也便于软件开发人员最终实现这些功能。在官方文档中用例图包含六个元素,分别是:参与者(Actor)、用例(Use Case)、关联关系(Association)、包含关系(Include)、扩展关系(Extend)以及泛化关系(Generalization)。但是有些UML的绘图工具多提供了一种直接关联关系(Directed Association)。

  1. 参与者:是指用户在系统中扮演的角色
  2. 用例:是指外部可见的系统功能,对系统提供的服务进行描述
  3. 关联关系:连接参与者和用例,表示该参与者代表的外部系统实体与该用例描述的系统需求有关
  4. 包含关系:是来自于用例的抽象,即从数个不同的Use Case中,分离出公共的部分,而成为可以复用的用例
  5. 扩展关系:表示某一个用例的对话流程中,可能会根据条件临时插入另外一个用例,而前者称为基础用例后者称为扩展用例
  6. 泛化关系:一个用例可以被特别列举为一个或多个用例,这被称为用例泛化

eg:用户管理的用例图如下所示,图中人形图标表示参与者,椭圆表示用例(图的出处请参见“总结与参考”)

主要内容回顾

1. 搞清哪个客户扮演哪个角色

2. 从客户的脑海中挖掘信息

3. 寻找关于用户角色、职责、现有流程和现有数据的文档

4. 观察客户的工作,学习他们的业务操作

5. 进行头脑风暴,把收集到的功能需求点按优先级分成第一、第二和第三级

6. 确认对客户需求的理解

7. 撰写需求文档,包含可验证的里程碑和用例

用例图参考

1. 初学UML之——-用例图(http://blog.csdn.net/dl88250/archive/2007/10/16/1826713.aspx

2. UML用例图(http://www.alisdn.com/wordpress/?p=1161

下一篇 数据库设计 Step by Step (6) —— 提取业务规则

数据库设计 Step by Step (4)——高级ER模型构件

阅读原文 转自博客园 知行思新

引言:数据库设计 Step by Step (3)中我们讨论了基本实体关系模型构件及其语义。这些概念非常重要,是今天这一讲的基础,在开始本文内容之前建议大家可以再回顾一下上一篇的内容。今天我们将讨论高级实体关系模型构件,与上一篇一起涵盖了ER模型构图的大部分内容。三元关系是今天这一讲的难点,大家可以重点关注。

泛化(Generalization):超类型与子类型

原始的ER模型已经能描述基本的数据和关系,但泛化(Generalization)概念的引入能方便多个概念数据模型的集成。

泛化关系是指抽取多个实体的共同属性作为超类实体。泛化层次关系中的低层次实体——子类型,对超类实体中的属性进行继承与添加,子类型特殊化了超类型。

ER模型中的泛化与面向对象编程中的继承概念相似,但其标记法(构图方式)有些差异。

下图表示员工与经理、工程师、技术员、秘书之间的泛化关系。Employee为超类实体,并包含共同属性,Manager、Engineer、Technician、Secretary都是Employee的子类实体,它们能包含自身特有的属性。

图1  Employee与Manager、Engineer、Technician、Secretary之间的泛化关系

泛化可以表达子类型的两种重要约束,重叠性约束(disjointness)完备性约束(completeness)

重叠性约束表示各个子类型之间是否是排他的。若为排他的则用字母“d”标识,否则用“o”标识(o -> overlap)。图1中各子类实体概念上是排他的。

对员工、客户实体进行泛化,抽象出超类实体个人,得到如下关系图。由于部分Employee也可能是Customer,故子类实体Employee与Customer之间概念是重叠的。

图2  Individual与Employee、Customer之间的泛化关系

完备性约束表示所有子类型在当前系统中是否能完全覆盖超类型。若能完全覆盖则在超类型与圆圈之间用双线标识(可以把双线理解为等号)。在图2中子类实体Employee与Customer能完全覆盖超类Individual实体。

聚合(Aggregation)

聚合是与泛化抽象不同的另一种超类型与子类型间的抽象。

泛化表示“is-a”语义,聚合表示“part-of”语义。聚合中子类型与超类型间没有继承关系。

聚合关系的标记法是在圆圈中标识字母“A”来表示。

下图表示软件产品由程序与用户手册组成。

图3  Software-product与Program、User’s Guide之间的聚合关系

三元关系(Ternary Relationships)

当通过二元关系无法准确描述三个实体间的联系时,我们需要使用三元关系。

三元关系中“连通数”的确定方法:

a) 以三元关系中的一个实体作为中心,假设另两个实体都只有一个实例

b) 若中心实体只有一个实例能与另两个实体的一个实例进行关联,则中心实体的连通数为“一”

c) 若中心实体有多于一个实例能与另两个实体实例进行关联,则中心实体的连通数为“多”

注:什么时候需要使用三元关系的实例请参看:数据库设计 Step by Step (3)中的“关系的度(Degree of a Relationship)”小节。关系的“连通数”概念请参看:数据库设计 Step by Step (3)中的“关系的连通数(Connectivity of a Relationship)”小节。

我们来看几个三元关系的实例,注意各个图中关系的度,并理解其中的语义。

图4  技术员在项目中使用手册的关系

图4中蕴含的语义为:

a) 一名技术员对于每一个项目使用一本手册

b) 每一本手册对于每一个项目属于一名技术员

c) 一名技术员可能在做多个项目,对于不同的项目维护不同的手册

用数学中的函数依赖表示图4的关系:

a) emp-id, project-name -> notebook-no

b) emp-id, notebook-no -> project-name

c) project-name, notebook-no -> emp-id

图5  员工被分配不同地点的项目之间的关系

图5中蕴含的语义为:

a) 每一个员工在一个地点只能被分配一个项目,但可以在不同地点做不同的项目

b) 在一个特定的地点,一个员工只能做一个项目

c) 在一个特定的地点,一个项目可以由多个员工来做

用数学中的函数依赖表示图5的关系:

a) emp-id, loc-name -> project-name

b) emp-id, project-name -> loc-name

图6  经理管理项目与工程师的关系

图6中蕴含的语义为:

a) 一名经理手下的一名工程师可能参与多个项目

b) 一名经理管理的一个项目可能会有多名工程师

c) 做某一个项目的一名工程师只会有一名经理

用数学中的函数依赖表示图6的关系:

a) project-name, emp-id -> mgr-id

图7  员工在项目中使用技能的关系

图7中蕴含的语义为:

a) 一名员工在一个项目中可以使用多种技能

b) 一名员工的一种技能可以在多个项目中使用

c) 一种技能在一个项目中可以被多名员工使用

图7各实体之间没有函数依赖

上述4种形式的三元关系,连通数为“一”的实体数量与该三元关系反映的函数依赖语义的数目一致。

三元关系也能有属性。属性值由三个实体的键的组合唯一确定。

n元关系(General n-ary Relationships)

三元关系可以扩展到n元关系,描述n个实体之间的关系。

一般而言,n元关系中每一个连通数为“一”的实体的键都会出现在一个函数依赖表达式的右侧。

对于n元关系,使用语言来表达其中的约束相对较为困难。建议使用数学形式即函数依赖(FD)来表现。

n元关系的函数依赖条目数量与关系图中“一”端实体的数量相同(0~n条)。

n元关系的函数依赖表达式包含n个元素,n-1个元素出现在表达式左侧,1个元素出现在右侧。

图8  n元关系图例

排他性约束(Exclusion Constraint)

一般(默认)情况下,多种关系之间是兼容的“或”关系,即允许任意或所有实体参与这些关系。

在某些情况下,多种关系之间是非兼容性“或”关系,即参与关系的实体只能选择其中一种关系,不能同时选择多种关系。

下图表示的语义为:一项工作任务要么被归为外部项目中,要么被归为内部项目中,不可能同时属于外部项目和内部项目。

图9  排他性约束关系图例

图9  排他性约束关系图例

我们对上一篇数据库设计 Step by Step (3)与本篇的重点内容做一个总的回顾

1. 我们讨论了ER模型及构图的基本概念

2. 一个实体可以是一个人,地方,东西或事件

3. 属性是实体的描述信息

4. 属性可以是唯一标识或非唯一的描述

5. 关系描述了实体之间“一对一”,“一对多”,“多对多”的联系

6. 关系的度反映了参与关系的实体数量,如二元关系,三元关系,n元关系

7. 角色(名)定义了一个实体在一个关系中所具有的功能

8. 关系的存在概念表示一个实体在关系中是强制存在还是可选的

9. 泛化允许把实体抽象成超类与子类

10. 三元关系可使用函数依赖来定义

下一篇:数据库设计 Step by Step (5)——理解用户需求

数据库设计 Step by Step (3)——基本ER模型构件

阅读原文 转自博客园 知行思新

引言:数据库设计 Step by Step (2)在园子里发表之后,收到了一些邮件,还有朋友直接电话我询问为什么不包含数据库物理设计方面的内容。我在这里解释一下,数据库物理设计与数据库产品是密切相关的,本系列的专注点是较为通用的数据库设计理念与方法,这也是国内软件项目中容易被忽视的一块。今天我们将学习实体关系(ER)模型构件及其语义,这是数据库逻辑设计的基础。内容可能有些枯燥,但却非常重要和有用。

由于内容比较多,我们将分两讲来学习实体关系模型构件。

今天我们先来学习基本实体关系模型。

实体关系(ER)模型的目标是捕获现实世界的数据需求,并以简单、易理解的方式表现出来。ER模型可用于项目组内部交流或用于与用户讨论系统数据需求。

ER模型中的基本元素

基本的ER模型包含三类元素:实体、关系、属性

图1 实体、关系、属性的ER构图

实体(Entities):实体是首要的数据对象,常用于表示一个人、地方、某样事物或某个事件。一个特定的实体被称为实体实例(entity instance或entity occurrence)。实体用长方形框表示,实体的名称标识在框内。一般名称单词的首字母大写。

关系(Relationships):关系表示一个或多个实体之间的联系。关系依赖于实体,一般没有物理概念上的存在。关系最常用来表示实体之间,一对一,一对多,多对多的对应。关系的构图是一个菱形,关系的名称一般为动词。关系的端点联系着角色(role)。一般情况下角色名可以省略,因为实体名和关系名已经能清楚的反应角色的概念,但有些情况下我们需标出角色名来避免歧义。

属性(Attributes):属性为实体提供详细的描述信息。一个特定实体的某个属性被称为属性值。Employee实体的属性可能有:emp-id, emp-name, emp-address, phone-no……。属性一般以椭圆形表示,并与描述的实体连接。属性可被分为两类:标识符(identifiers)描述符(descriptors)。Identifiers可以唯一标识实体的一个实例(key),可以由多个属性组成。ER图中通过在属性名下加上下划线来标识。多值属性(multivalued attributes)用两条线与实体连接,eg:hobbies属性(一个人可能有多个hobby,如reading,movies…)。复合属性(Complex attributes)本身还有其它属性。

辨别强实体与弱实体:强实体内部有唯一的标识符弱实体(weak entities)的标识符来自于一个或多个其它强实体。弱实体用双线长方形框表示,依赖于强实体而存在。

深入理解关系

关系在ER模型中扮演了非常重要的角色。通过ER图可以描述实体间关系的度连通数存在性信息

我们一一来解释这些概念。首先我们来看一下关系在ER图中的各种语义。

图2 关系的度、连通数、存在性

图2 关系的度、连通数、存在性

关系的度(Degree of a Relationship)

表示关系所关联的实体数量。二元关系与三元关系的度分别为2和3,以此可以类推至n元。二元关系是最常见的关系。

一个Employee与另一个Employee之间的领导关系称为二元回归关系。如图2中所示,Employee实体通过关系manages与自身连接。由于Employee在这一关系中扮演两个角色,故标出了角色名(manager和subordinate)。

三元关系联系三个实体。当二元关系无法准确描述关联的语义时,就需要使用三元关系。我们来看下面这个例子,下图(1)能反映出一个Employee在某个Project中使用了什么Skill。下图(2)只能看出Employee有什么Skill,参与了哪些Project,但无法知道在某个Project中使用的特定Skill。

图3 三元关系蕴含的语义

需要注意的是有些情况下会错误的定义三元关系。这些三元关系可分解为2个或3个二元关系,来达到化简与语义的纯净。以后的博文中会进一步详细讨论三元关系。

一个实体可以参与到任意多个关系中。每个关系可以联系任意多个元(实体),而且两个实体之间也能有任意多个二元关系。

3 三元关系蕴含的语义

关系的连通数(Connectivity of a Relationship)

表示关系所关联的实例数量的约束。

连通数的值可以是“一”或“多”。“一”这一端,在ER图中通过在实体与关系间标记“1”表示。“多”一端标记“N”表示。如图2中关系连通数部分,“一”对“一”:Department is managed by Employee;“一”对“多”:Department has Employees;“多”对“多”:Employee may work on many Projects and each Project may have many Employees。

有些情况下最大连通数是确定的,可以用数值代替N。如:田径队队员有12人。

关系的属性

关系也能有属性。如下图4所示,某员工参与某项目的起始日期,某员工在某项目中被分配的任务只有放在关系works-on上才有意义。

图4 关系的属性

需要注意的是关系的属性一般出现在“多”对“多”的二元关系或三元关系上。一般“一”对“一”或“一”对“多”关系上不会放属性(会引起歧义,通俗说法就是没有中间表)。而且这些属性可以移至一端的实体中。如下图5所示,如果部门与员工(经理)之间是“一”对“一”关系,在建模中可能把start-date作为关系is managed by的属性(表示被接管的时间),这个属性可以移至Department或Employee实体中。

大家可以思考一下如果部门和经理之间是“多”对“多”关系,即交叉管理,那又会怎样?

图5 部门与经理之间的一对一管理关系

关系中实体的存在性(Existence of an Entity in a Relationship)

关系中实体的存在性可以是强制的或可选的。当关系中的某一边实体(无论是“一”或“多”端)必须总是存在,则该实体为强制的。反之,该实体为可选的。

在实体与关系之间的连接线上标识“0”来表示可选存在性。含义是最小连通数为0。

强制存在性表示最小连通数为1。在存在性不确定或不可知的情况下,默认最小连通数为1。

在ER图中最大连通数显式地标识在实体旁边。如图6所示,其蕴含的语义为一个Department有且只有一个Employee来当经理,一个Employee可能是一个Department的经理,也可能不是。

图6 关系中实体的存在性

其他概念数据模型标记法

前文中使用的ER构图方法是Peter Chen 1976年提出的。在现代数据库设计领域,还有其他多种ER模型标记法。

我们来看一下另一种使用较多的标记法,“crow’s-foot”(鱼尾纹)标记法,并与前面介绍的标记法进行一个简单对比。

学习每一种标记法没有意义。在你的组织中推广应用一种标记法,使其成为大家共通的“语言”。

图7 Chen式标记法与crow’s-foot标记法对照

主要内容回顾

1. 组成ER模型的基本元素包括:实体、关系、属性

2. 深入理解关系中包含的语义:关系的度、关系的连通数、关系的存在性

3. 了解ER模型的不同标记法,掌握其中一种标记法,并在你的项目中推广使用

实体关系模型参考

1. Entity-relationship model(http://en.wikipedia.org/wiki/Entity-relationship_model

2.  Entity-relationship modelling(http://www.inf.unibz.it/~franconi/teaching/2000/ct481/er-modelling/

下一篇:数据库设计 Step by Step (4)——高级ER模型构件

数据库设计 Step by Step (2)——数据库生命周期

阅读原文  转自博客园  知行思新

引言:数据库设计 Step by Step (1)得到这么多朋友的关注着实出乎了我的意外。这也坚定了我把这一系列的博文写好的决心。近来工作上的事务比较繁重,加之我期望这个系列的文章能尽可能的系统、完整,需要花很多时间整理、思考数据库设计的各种资料,所以文章的更新速度可能会慢一些,也希望大家能够谅解。

系列的第二讲我们将站在高处俯瞰一下数据库的生命周期,了解数据库设计的整体流程

数据库生命周期

大家对软件生命周期较为熟悉,数据库也有其生命周期,如下图所示。

图(1)数据库生命周期

数据库的生命周期主要分为四个阶段:需求分析、逻辑设计、物理设计、实现维护

这个系列的博文将主要关注数据库生命周期中的前两个阶段(需求分析、逻辑设计)。如图中红色框出的部分。

数据库的物理设计,包括索引的选择与优化、数据分区等内容。这些内容也非常丰富,而且可以自成体系,园子里也有很多好文章,故在本系列中不作主要关注。本文最后将给出一些链接供大家参考。

数据库生命周期的四个阶段又能细分为多个小步骤,我们配合图(1)来看看每一小步包含的内容。

阶段1 需求分析

数据库设计与软件设计一样首先需要进行需求分析。

我们需要与数据的创造者和使用者进行访谈。对访谈获得的信息进行整理、分析,并撰写正式的需求文档。

需求文档中需包含:需要处理的数据数据的自然关系数据库实现的硬件环境软件平台等;

阶段2 逻辑设计

使用ERUML建模技术,创建概念数据模型图,展示所有数据以及数据间关系。最终概念数据模型必须被转化为范式化的表

数据库逻辑设计主要步骤包括:

a) 概念数据建模

在需求分析完成后,使用ER图或UML图对数据进行建模。使用ER图或UML图描述需求中的语义,即得到了数据概念模型(Conceptual Data Model),例如:三元关系(ternary relationships)、超类(supertypes)、子类(subtypes)等。

eg:  零售商视角,产品/客户数据库的ER模型简图

图(3)阶段2(a) 概念数据建模

b) 多视图集成

当在大型项目设计或多人参与设计的情况下,会产生数据和关系的多个视图。这些视图必须进行化简与集成,消除模型中的冗余与不一致,最终形成一个全局的模型。多视图集成可以使用ER建模语义中的同义词(synonyms)、聚合(aggregation)、泛化(generalization)等方法。多视图集成在整合多个应用的场景中也非常重要。

eg: 集成零售商ER图与客户ER图
图(4)以客户为关注点绘制的ER图

注:现在市面上有许多辅助建模工具可以绘制ER图。使用Sybase的PowerDesigner绘制与图(4)相同语义的ER图如下:

其标记法与图(4)中略有不同,这将在今后的博文中加以说明。

这里需要指出的是辅助软件的使用不是设计的核心,大家不要被这些工具迷惑。所以后文中我们将主要使用手绘。只要掌握了ER图的语义,使用这些软件都不会是件难事。

集成零售商ER图与客户ER图

图(5) 阶段2(b) 多视图集成

c) 转化概念数据模型为SQL表

根据映射规则,把ER图中的实体与关系转化为SQL表结构。在这一过程中我们将识别冗余的表,并去除这些表。



图(6) 阶段2(c)转化概念数据模型为SQL表

d) 范式化

范式化是数据库逻辑设计中的重要一步。范式化的目标是尽可能去除模型中的冗余信息,从而消除关系模型更新、插入、删除异常(anomalies)。

讲到范式化就会引出函数依赖(Functional Dependency)这一概念。函数依赖(FDs)源自于概念数据模型图,反映了需求分析中的数据关系语义。不同实体之间的函数依赖表示各个实体唯一键之间的依赖。实体内部也有函数依赖,反映了实体中键属性与非键属性之间的依赖。在保证数据完整性约束的前提下,基于函数依赖对候选表进行范式化(分解、降低数据冗余)。

图(7) 阶段2(d)范式化

阶段3 物理设计

数据库物理设计包括选择索引,数据分区与分组等。

逻辑设计方法学通过减少需要分析的数据依赖,简化了大型关系数据库的设计,这也减轻了数据库物理设计阶段的压力。

1. 概念数据建模和多视图集成准确地反映了现实需求场景

2. 范式化在模型转化为SQL表的过程中保留了数据完整性

数据库物理设计的目标是尽可能优化性能。

物理设计阶段,全局表结构可能需要进行重构来满足性能上的需求,这被称为反范式化。

反范式化的步骤包括:

1. 辨别关键性流程,如频繁运行、大容量、高优先级的处理操作

2. 通过增加冗余来提高关键性流程的性能

3. 评估所造成的代价(对查询、修改、存储的影响)和可能损失的数据一致性

阶段4 数据库的实现维护

当设计完成之后,使用数据库管理系统(DBMS)中的数据定义语言(DDL)来创建数据结构。

数据库创建完成后,应用程序或用户可以使用数据操作语言(DML)来使用(查询、修改等)该数据库。

一旦数据库开始运行,就需要对其性能进行监视。当数据库性能无法满足要求或用户提出新的功能需求时,就需要对该数据库进行再设计与修改。这形成了一个循环:监视 –> 再设计 –>  修改 –> 监视…

在进行数据库设计之前,我们先回顾一下关系数据库的相关基本概念。

这里只做一个提纲挈领的简介,大家可以根据相应的线索进行扩展。

表、行、列

关系数据库可以想象成表的集合,每个表包含行与列。(可以想象成一个Excel workbook,包含多个worksheet)。

表在关系代数中被称为关系,这也是关系数据库名称的起源(不要与表之间的外键关系混淆)。

列在关系代数中被称为属性(attribute)。列中允许存放的值的集合称为列的域(域与数据类型密切相关,但并不完全相同)。

行在关系代数中的学名是元组(tuple)。

关系数据库的理论基础来自于“关系代数”。但在关系代数中,一个集合的各个元组没有次序的概念,在关系数据库中为了方便使用,定义了行的次序。

键、索引

键是一种约束,目的是保证数据完整性

索引是数据的物理组织形式,目的是提高查询的性能

约束

基本约束

not null constraint, domain constraint

检查约束(Check Constraints)

eg: Salary > 0

主键约束(Primary Key Constraints)

实体完整性(entity integrity),没有两条记录是完全相同的,组成主键的字段不能为null

唯一性约束(Unique Constraints)

外键约束(Foreign Key Constraints)

也被称为引用完整性约束,eg:

关系数据库操作

1.选择(Selection)

2.映射(Projection)

3.联合(Union)

4.交集(Intersection)

5.差集(Difference)

6.笛卡尔积(Cartesian Product)

7.连接(Join)

上述7种是最基本的关系数据库操作,对应于集合论中的关系运算。

有些书籍中还会加入改名(Rename),除(Divide)等关系操作。


主要内容回顾

1. 数据库生命周期的四个阶段:需求分析、逻辑设计、物理设计、实现维护。

2. 关系数据库的理论基础是关系代数。

数据库物理设计参考资料

第一个链接是我针对查询优化作的读书笔记,后三个链接是SQLServerCentral中几篇关于索引的文章(需要简单注册后才能看到全文)

1. 查询优化系列(查询优化(1)查询优化(2)查询优化(3)查询优化(4)查询优化(5)——总结

2. Part 1 – The basics of indexes

3. Part 2 – The Clustered Index

4. Part 3 – The Non-clustered index

关联阅读

数据库设计 Step by Step (3)——基本ER模型构件

数据库设计 Step by Step (1)——扬帆启航

阅读原文 转自博客园 知行思新

引言:一直在从事数据库开发和设计工作,也看了一些书籍,算是略有心得。很久之前就想针对关系数据库设计进行整理、总结,但因为种种原因迟迟没有动手,主要还是惰性使然。今天也算是痛下决心开始这项卓绝又令我兴奋的工作。这将是一个系列的文章,我将以讲座式的口吻展开讨论(个人偷懒,这里的总结直接拿去公司培训新人用)。

系列的第一讲我们先来回答下面几个问题

数据库是大楼的根基

大多数程序员都很急切,在了解基本需求之后希望很快的进入到编码阶段(可能只有产出代码才能反映工作量),对于数据库设计思考得比较少。

这给系统留下了许多隐患。许多软件系统的问题,如:输出错误的数据,性能差或后期维护繁杂等,都与前期数据库设计有着密切的关系。到了这个时候再想修改数据库设计或进行优化等同于推翻重来。

我经常把软件开发比作汽车制造。汽车制造会经过图纸设计,模型制作,样车制造,小批量试生产,最后是批量生产等步骤。整个过程环环相扣,后一过程是建立在前一过程正确的前提基础之上的。如果在图纸设计阶段发现了一个纰漏,我们可以重新进行图纸设计,如果到了样车制造阶段发现这个错误,那么我们就要把从图纸设计到样车制造的阶段重来,越到后面发现设计上的问题,所付出的代价越大,修改的难度也越大。

数据库是整个应用的根基,没有坚实的根基,整个应用也就岌岌可危了。

强大的数据库面对不良设计也无能为力

现代数据库管理系统(DBMS)提供了方便的图形化界面工具,通过这些工具可以很方便的创建表、定义列,但我们设计出的结构好吗?

关系数据库有许多非常好的特性,但设计不当会使这些特性部分或完全的丧失。

我们来看看以下几个数据库不良设计造成的场景:

1. 数据一致性的丧失

一个订单管理系统,维护着客户和客户下的订单信息。使用该系统的用户在接到客户修改收货地址的电话后,在系统的客户信息页面把该客户的收货地址进行了修改,但原先该客户的订单还是送错了地址。

2. 数据完整性的丧失

公司战略转移,准备撤出某地区。系统操作人员顺手把该地区的配置信息在系统中进行删除,系统提示删除成功。随后问题就来了,客服人员发现该地区的历史订单页面一打开就出错。

3. 性能的丧失

一个库存管理系统,仓库管理员使用该系统记录每一笔进出货情况,并能查看当前各货物的库存情况。在系统运行几个月后,仓库管理员发现打开当前库存页面变得非常慢,而且整个趋势是越来越慢。

上面这些场景都是由于数据库设计不当造成的,根源包括:设计时引入了冗余字段,没有设计合理的约束,对性能没有进行充足设计等,上面的例子也只是沧海一粟。

数据库平台无关性

我在这个系列博客里讨论的数据库设计不针对任何一个关系数据库产品。无论你使用的是Oracle,SQL Server,Sybase,亦或是开源数据库如:MySQL,SQLite等,都可以用来实践我们这里讨论的设计方法和设计理念,设计是这个系列博文的核心和灵魂。

注:在文中我会选用一个数据库产品来进行演示,大家可以选用自己熟悉的数据库产品来实验。本文最后会给出一些免费数据库产品的链接,大家可以下载学习。

一起学习共同进步

无论你是数据库设计师,应用架构师,软件工程师,数据库管理员(DBA),软件项目经理,软件测试工程师等项目组成员,都能从该系列博文中有所收获。大家一起讨论,共同进步。

内容涉及领域

我对这一系列博文现在的设想是涉及数据库设计的整个过程。从需求分析开始,到数据库建模(概念数据建模),进行范式化,直至转化为SQL语句。

在我们一头扎进数据库设计之前,我们先了解一下除了关系型数据库之外的数据存储方式。

平面文件(Flat File)

包括以.txt和.ini结尾的文件。

eg: 一个.ini文件的内容:

————————————————————

[WebSites]

MyBlog=http://www.cnblogs.com/DBFocus

[Directorys]

Image=E:\DBFocus Project\Img

Text=E:\DBFocus Project\Documents

Data=E:\DBFocus Project\DB

————————————————————

优点:

文件的存储形式非常简单,普通的编辑器都能对其进行打开、修改

缺点:

无法支持复杂的查询

没有任何验证功能

对平面文件中间的内容进行插入、删除操作其实是重新生成了一个新文件

适用场景:

存放小量,修改不频繁的数据,如应用配置信息

Windows注册表

错误的修改Windows注册表会引起系统的紊乱,故不建议把很多数据存放在注册表中。

Windows注册表为树形结构,存放着一些系统配置信息和应用配置信息。

通过把不同的配置存放在注册表的不同分支上,使得应用程序公共配置信息与用户个人配置信息分离。

eg:某文档版本管理系统,能通过配置与本主机上安装的文件比较器建立关联进行文档比较。这是一个公共配置信息,文件比较器路径可以存放在注册表的HKEY_LOCAL_MACHINE\SOFTWARE分支下。

同时该文档版本管理系统能记录用户最近打开的10个文档路径。这是用户个人配置信息,对于不同的Windows用户最近打开的10个文档可以不同,这些配置信息可存放在注册表的HKEY_CURRENT_USER\Software分支下。

Excel表单(Spreadsheets)

优点:

Excel 非常普及,用户对于Spreadsheet的表现形式非常熟悉

可以进行简单统计,方便出各种图表

缺点:

不适用于许多Spreadsheet之间关系复杂的情况

无法应对复杂查询

数据验证功能弱

适用场景:

数据量不是非常大的办公自动化环境

XML

XML是一种半结构化的数据。相比于超文本标记语言(HTML),其标签是可以自行定义的,即可扩展的。

eg:一个XML文件内容

—————————————————–

<?xml version=”1.0” encoding=”UTF-8” ?>

<ClassSchedule>

<Class Name=“Psychology” Room=”Field 3”>

<Instructor>Richard Storm</Instructor>

<Students>

<Student>

<FirstName>Ben</FirstName>

<LastName>Breaker</LastName>

</Student>

<Student>

<FirstName>Carol</FirstName>

<LastName>Enflame</LastName>

<NickName>Candy</NickName>

</Student>

</Students>

</Class>

</ClassSchedule>

—————————————————–

XML文件有几个特点。

首先,XML标签要求严格对应,且不能出现交错的现象。

其次,XML文件必须有一个根节点,该节点包含所有其他元素。

第三,同级别的不同节点内不必包含相同的元素,如上例中第二个学生Carol有一个特别的节点NickName。这个特性使得在某些场景中XML比关系数据库更能应对变化。

优点:

自然的层次型结构

文本内容通过标签是自解释的

通过XSD(XML Schema语言)可以验证XML的结构

有许多辅助型技术如:XPath, XQuery, XSL, XSLT等

一些商业数据库(如Oracle,SQL Server)已支持XML数据的存储与操作

缺点:

数据的冗余信息较多

无法支持复杂的查询

验证功能有限

对XML中间的内容进行插入、删除操作其实是重新生成一个新文件

适用场景:

适合存放数据量不大,具有层次型结构的数据,如树形配置信息

NoSQL数据库

非关系型数据库我接触的不是很多,除了给出一些产品名称之外不做很多展开。园子里已有一些文章,本文最后也给出了链接供大家学习、研究。

1. Key-Value数据库

Redis, Tokyo Cabinet, Flare

2. 面向文档的数据库

MongoDB, CouchDB

3. 面向分布式计算的数据库

Cassandra, Voldemort

这几年NoSQL非常热。我认为NoSQL并不是“银弹”,在某些SNS应用场景中NoSQL显示了其优越性,但在如金融行业等对数据的一致性、完整性、可用性、事务性高要求的场景下,现在的NoSQL就未必适用。我们应充分分析应用的需求,非常谨慎地选择技术和产品。

主要内容回顾

1.数据库设计对于软件项目成功的关键作用

2.本课程与数据库产品无关,核心是设计的理念和方法

3.各种数据存储所适用的场景

参考资料

1. Oracle Database 10g Express Edition

2. SQL Server 2008 R2 Express – Overview

3. SQLite Home Page

4. NoSQL数据库笔谈

下一篇:数据库设计 Step by Step (2)——数据库生命周期