数据库设计 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)——数据库生命周期

曳光弹

曳光弹

曳光弹和常规子弹交错装在弹药带上,发射时会照亮弹道路线,如果曳光弹击中目标,那么常规子弹也会击中目标,比提前费力计算更可取,可以及时获得反馈。

类比软件开发,曳光弹适用于新项目。当你构建从未构建过的东西时,与枪手一样,你也没法在黑暗中击中目标。因为你的用户从未见过这样的系统,他们的需求可能会含糊不清。因为你在使用不熟悉的算法、技术、语言或库,你面对这当量未知的事物。同时因为完成项目需要时间,在很大程度上能够确知,你的工作环境将在你完成之前发生变化。

经典的作法是把系统定死,制作大量的文档,注意列出每项需求、确定所有未知因素。限定环境,预先进行大量计算。这种方式非常低效。因为永远有你考虑不到的情况。

注重实效的作法是使用曳光弹,我们要找到某种东西,让我们快速直观和可重复的从需求出发,满足最终系统的某个方面要求。曳光代码并非用过就扔的代码,你编写它是为了保留它。它只是功能不全,可以逐步完善达到最终目标。

曳光开发与项目永不会结束的理念是一致的:总有改动需要完成,总有功能需要增加。这是一个渐进的过程。曳光弹算一种敏捷开发方法。

曳光开发不一定命中目标达到想要的效果。

参考

《程序员的修炼之道从小工到专家》

关于

我是谁

后端和运维为主程序员,面向业务和问题编程,专业:计算机网络技术

爱好写代码,研究技术,学习科普知识,K歌,宅

我的Github https://github.com/yangliuan 自己的业务总结和学习项目和常用工具

我的简历 https://hacknical.com/yangliuan/resume

做一些总结备忘和笔记

职业规划

编程语言以php+javascript为主,业务方向以服务端开发+运维+网络安全的综合型应用程序员

扎实的基础:

数据结构+算法 网络协议tcp udp http websocket webrtc

面向对象相关知识:

设计模式 SOLID设计原则

需要掌握的技术栈

php: laravel swoole workman 和各种常用库 要具备开发库的能力 系统设计 网络编程能力

javascript: vue vue-element-admin electron 要具备开发后台管理的能力

web服务器

nignx openresty tengine 掌握熟练使用 apache

数据库

mysql 数据库设计 锁机制 查询优化 分库分表和读写分离的实际应用(有具备该功能的云数据库)

elasticsearch 熟练使用 关系型数据库的实体度和实体连通数 如何对应在es中存储和查询

redis memcached 熟练使用 常见需求的应用案例和使用方式

队列和消息中间件

kafka rabbitmq 熟练使用 常见需求的应用案例和使用方式

运维

linux docker kubernetes 生产环境的部署和运维 2台服务器用云镜像 3台以上用容器

掌握基本的压测工具和方法

网络安全

网络安全基础知识 常见WEB漏洞和攻击方式 如何更安全的设计接口 掌握基本的渗透测试工具

破窗户效应

此理论认为环境中的不良现象如果被放任存在,会诱使人们仿效,甚至变本加厉。以一幢有少许破窗的建筑为例,如果那些窗不被修理好,可能将会有破坏者破坏更多的窗户。最终他们甚至会闯入建筑内,如果发现无人居住,也许就在那里定居或者纵火。一面墙,如果出现一些涂鸦没有被清洗掉,很快的,墙上就布满了乱七八糟不堪入目的东西;一条人行道有些许纸屑,不久后就会有更多垃圾,最终人们会视若理所当然地将垃圾顺手丢弃在地上。这个现象,就是犯罪心理学中的破窗效应。

在项目中,一旦开始松懈,出现了烂代码,最终项目的代码将会变烂。

参考

《程序员的修炼之道从小工到专家》

墨菲定律 (Murphy’s Law)

或许是所有的定律中最广为人知的,因为它不仅仅适用于软件开发领域。

凡是可能出错的事就一定会出错。

衍生定律:说脏话是唯一一门程序员用得都很流畅的语言。

推论:计算机会按照你写出来的方式运行,而不是你臆想出来的。

防御性编程、版本控制、测试驱动开发、模型驱动开发等等都是预防墨菲定律很好的做法。

布鲁克斯法则(Brook’s Law)

大多数开发人员都会经历过布鲁克斯定律:

向一个延期的项目增加人手只会让它延期得更加厉害

如果一个项目进展落后了,仅仅增加人力很有可能会带来灾难性的后果。

相反,提高编程效率、审查软件开发方法和技术架构是否合理,几乎总是会比增加人力带来更好的效果。如果没有,这可能意味着霍夫施塔特定律在起作用。

出自《人月神话

百度百科

维基百科

霍夫斯塔特定律 (Hofstadter’s Law)

霍夫斯塔特定律是由道格拉· 霍夫斯塔特(Douglas Hofstadter) 提出,并且以他的名字来命名的。

不要将这个定律与《生活大爆炸》中的伦纳德·霍夫斯塔特混为一谈。即使他的话对你们一些人或许有用。

这个定律是这么说的:

事情总是要花费比你预想更长的时间,即使你把霍夫斯塔特定律也考虑在内。

这条定律的递归性反映出,即使付出最大的努力,也知道任务是复杂的,去精确地估算它依然是非常难的,所以要给估算留一个缓冲区出来。 

康威定律 (Conway’s Law)

软件的任何一部分都反应了创建它的组织结构

康威定律 (康威法则 , Conway’s Law) 是马尔文·康威1967年提出的:

“设计系统的架构受制于产生这些设计的组织的沟通结构。”——M. Conway[1]

即系统设计本质上反映了企业的组织机构。系统各个模块间的接口也反映了企业各个部门之间的信息流动和合作方式。

康威定律源于模块的设计者需要互相之间频繁沟通。而跨部门交流比较难。[2]

埃里克·雷蒙在《新黑客词典》中,称康威定律指出了软件架构与软件团队架构的等价(congruent)。例如,“如果你有4个团队在做一个编译器,你会得到一个4遍处理的编译器”。[3][4]

James O. CoplienNeil B. Harrison在《敏捷软件开发的组织模式》中写道:

“如果团队、部门、子部门等的组织结构没有紧密反映产品的必要组成或产品组成的关系,那么项目将会遇到麻烦。因此,应该确保组织结构兼容于产品架构。”[5]

康威的原文中提出的各定律[1]

  • 第一定律 组织沟通方式会通过系统设计表达出来
  • 第二定律 时间再多一件事情也不可能做的完美,但总有时间做完一件事情
  • 第三定律 线型系统和线型组织架构间有潜在的异质同态特性
  • 第四定律 大的系统组织总是比小系统更倾向于分解

Eric Hollnagel在2009年的《Efficiency-Effectiveness Trade Offs》一书中类似的论点:

   Problem too complicated? Ignore details.
   Not enough resources?Give up features.

或者更清楚一点:

组织形式等同其设计的系统架构

许多组织都根据他们的技能来划分团队。因此会有前端开发、后端开发和数据库开发组成的团队。这会导致某人想要修改一个不属于自己领域的东西会很难。

最好是按照有边界的上下文(bounded context)来规划团队,并且越来越多的组织者也正在这么做。像微服务这样的架构围绕服务边界而不是孤立的技术体系划分来组织他们的团队。

康威定律带来的具体的实践建议就是:你想要什么样的系统设计,就架构什么样的团队,这会带来事半功倍的效果。