数据库设计 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)来规划团队,并且越来越多的组织者也正在这么做。像微服务这样的架构围绕服务边界而不是孤立的技术体系划分来组织他们的团队。

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