您还未登录! 登录 | 注册 | 帮助  

您的位置: 首页 > 软件开发专栏 > 数据库 > 正文

躲坑!数据库设计的九大常见错误

发表于:2019-01-30 作者:陈峻编译 来源:51cto

引言:本文向您介绍在数据库设计中常见的九种错误,希望能够帮你在躲开这些坑点的同时,构建出真正适合项目预期的数据库。

作为一名数据库设计人员,在您负责某个数据库项目时,难免会在初期设计的过程中,以及将数据库部署到生产环境之后,遇到不同的挑战。其中的一些很可能源自数据库的设计疏漏。也就是说,您在初期所做出的某些决策,很可能会对数据库的最终运行情况产生深远的影响。因此,为了躲避这些坑点的出现,让我们来讨论一下数据库设计中常见的九大错误吧。

1. 不佳的规划

正如在盖房子时,您不可能要求建筑工人在一小时之内就铺设好地基那样,您需要事先规划好房屋的设计图纸。同理,您对数据库的初始设计和计划越周全,您的最终系统和服务的性能才会越好。

因此,一个具有前瞻性的数据库,绝不是由某些临时想法拼凑而成。不佳的设计很可能会导致数据库本身的结构性问题,而一旦它被部署到生产环境中,我们将面临着替换和调整成本高昂的窘境。虽然我们无法预料到数据库将来可能出现的每一个问题,但是良好的前期规划,确实能降低推倒重来的风险。

2. 未能理解数据的意图

无论是存储个人数据的小型数据库,还是处理复杂信息的大型企业级数据库,每一种类型的创建与使用往往都是为了满足某个明确的数据意图。因此,设计人员只有真正理解了数据库的使用目的,才能根据这些目标进行最佳匹配模式的设计。

可见,他们需要问出的关键问题包括:数据的性质与类型、获取的方式、存储和检索的频率、数量、以及与之对应的各种应用程序。例如,那些需要在每日下班后手动录入信息的数据库,与能够将数据实时自动地捕获并存储的工业级复杂数据库相比,无论是在设计模型还是数据体量上,都是不一样的。

因此,设计的关键就在于确保数据处置的效率、可用性和安全性(请参见“PostgreSQL安全性”, https://www.datasunrise.com/datasunrise-for-postgresql/)。倘若盲目地追求数据库的大而全,反而是不切实际,而且不能够满足数据的具体应用需求。

3. 标准化不足

数据库设计并非是一个严格确定的过程。遵循相同设计规则的两位开发人员,往往不一定会设计出相同的数据布局。这主要取决于各种软件工程项目自身的创新性和数据库在其中所扮演的作用。尽管如此,一些与设计有关的核心原则,还是能够对于确保数据库的最佳性能起到关键性作用的。而其中一项便是:规范化。数据的规范化特指:将数据表分解成为多个组成部分的技术。您可以持续进行此项操作,直到每一个数据表都只表示一种事物,而每一列都只代表该事物的某一项属性为止。

事实上,SQL主要就是建立在对于规范化数据集的读取和操作基础上的。您可以使用FROM子句从一个表中提取数据,并使用JOIN将其添加到另一个表的内容之中。您可以通过生成各种数据表来表示数据的类型。因此,SQL的附加功能对于数据库的开发和性能都是至关重要的。

索引通过与键值的完全同步,来增强其效果。当您必须使用LIKE、CHARINDEX、SUBSTRING、以及类似的命令来解析某一列的组合值时,SQL语句通过分解,以减少数据被搜索的次数。

因此,规范化数据库对于简易开发和保持高性能都是至关重要的。我们可以根据不同的标准化水平,来满足数据库相关记录的插入、更新、查询和删除等需求。业界广为接受的最佳实践是:数据库必须至少达到第三范式(Normal Form,3NF)的标准化水平。当然,第四(4NF)和第五(5NF)范式也是非常实用且易于理解的。

4. 多余的记录

多余的表和字段对于数据库设计人员和管理员来说简直是噩梦。它们消耗有限的系统资源,来保障系统整体的安全性、同步性和备份能力。特别是对于某些大型数据库来说,它们的冗余字段记录可能会达到几百万条,这对于计算资源的开销显然是相当庞大的。它们在增加数据库本身体积的同时,不但降低了系统的运行效率,而且提高了数据受损的潜在风险。

在此,我们并不是说数据记录的冗余没有必要,而是说:应当根据规则与策略,在做好相关记录的基础上实现数据的冗余,并且在超过保存期限和适用条件时,由数据库管理员及时予以删除或销毁。

5. 不佳的索引

无论是用户还是应用程序,都可能会需要查询某个数据表的多个列值。然而,随着表中行记录的增加,相应的查询时间也会随之稳步上升。因此,为了加快查询的速度、并减少由表容量所产生的影响,我们需要通过对数据表的列进行索引,以便在调用SELECT查询时,表中的相对应记录条目能够实现“秒回”。

不过对于SELECT函数的加速,通常会导致有更多INSERT、UPDATE和DELETE命令的产生。这很大程度上是因为:索引本身就需要不断地与数据库的内容相同步,而此类操作就意味着会产生大量的数据库引擎开销。因此,颇具讽刺意味的是:您对加速SELECT查询的尝试,可能会反而导致数据库整体速度的变慢。这正是过度索引的经典案例。

解决上述问题的方法是:为所有列提供单一的索引,以用于查询表中的不同主键。您也可以按照从最常用到最少使用的不同列,进行降序排序。总之,构建索引是门技术活,需要您去花时间总结和调整。

6. 所有域值的单一表

包罗万象的域表(domain table)并非是数据库设计的最佳方法。记住,关系型数据库的构建理念是:数据库中的每个对象都只代表一个事物,不可出现任何指代不清的数据集。通过导航主键、表名、列名、以及各种关系,应用能够快速地解读出数据集的含义。尽管如此,在进行数据库设计时,许多人总会情不自禁地滑向:数据表越来越多,数据库越来越复杂和混乱的深渊。

过去,业界的普遍做法是将多张表压缩到一张表之中,进而简化设计。但是这往往会带来效率低下、且难以操作等问题。而且SQL代码会随着变长,可读性也会有所下降。可见单一域表貌似一个抽象的文本容器,但它的确不是数据库设计的最佳方式。

那么,作为规范化的一部分,我们需要通过数据隔离和分解的方法,让每一行都只代表一个事物,同时让多个域表相互区别不同的事物。其好处在于:

  • 让数据的查询更加容易。
  • 使用外键约束来更自然地验证数据,而这正是单域表设计所无法实现的。因为在单域表中,每张表所需的各种键会变得难以维护。
  • 每当您想为某个对象添加多种数据时,您只需简单地增加一到多列便可。
  • 小型域表(small-domain tables)适合于存储在硬盘的单页上,而大型域表很可能会扩展到多个磁盘的多个扇区里。显然,将表存放在单页中就意味着我们可以通过对单个磁盘的读取,以快速提取数据。
  • 因为这些域表很可能具有相同的底层用法与结构,因此拥有多个域表并不会妨碍您为所有的行启用同一编辑器。

7.不佳或不一致的命名规则

数据库设计人员和开发人员经常过于关注自己眼前的技术。而那些命名规则之类的非技术方面,往往会被他们置于优先级列表的最底层,或甚至完全被忽略掉。而这恰恰容易造成灾难性的恶果。

客观上说虽然命名规则可以由设计人员自行决定,但事实上,它对于数据库文档的重要程度还是不言而喻的(我们将在下面探讨不佳的文档)。由于数据库设在系统中相对持久和稳定,因此命名规则可以让那些没有参与过该构建项目的人员(如:后继的系统管理员、程序员、甚至是用户),不需要翻阅上千页的文档,就能够容易且快速地理解数据表与列的含义。当然,关于如何准确地命名各种数据表及其细节,目前业界尚无定论。

因此,最重要的就是要讲求“一贯性”。一旦您确定按照某个特定的方式来命名自己的对象,那么就请在整个数据库中贯彻该规则。对于数据表名称而言,我们应当尽可能让它能够完整或简约地描述所表示的对象,而每个列的名称则能够表示对象的属性。对于简单的数据库来说,这并不难以被实现;而对于需要构建相互引用关系的复杂数据表而言,严格遵循命名规则就是一件比较繁琐的事情了。

值得注意的是:此类规则不应该对列名或表名的字符长度有过分的限制,而且要避免使用那些不易理解、或记忆的首字母缩略词汇。例如:我们很难猜测出列名为CUST_DSCR的含义;而CUSTOMER_DESCRIPTION则会更好地表示出列名称的意义。

同时,我们也要避免重复。如果表的名称为“Students”,那么我们只需采用Name、 Address和Grade作为列名称便可,而不必重复地使用StudentName、StudentAddress或StudentGrade。当然,我们也不应该擅自使用那些保留词。如果您将某个列命名为“Index”,那么可能会给系统造成混淆,并产生不必要的错误。因此,我们可以使用诸如StudentIndex之类的描述性前缀。

8. 不佳的文档

我们在上面提到过,数据库的命名规则往往会体现在相关的文档中。这些看似微不足道的文档准备工作,却时常让一些优秀的数据库设计“身败名裂”。在系统运营的过程中,不佳的文档会极大地阻碍运维团队进行各种故障排除、架构改进、升级和连续性保证等工作。

数据库设计者应当假想:如果自己某一天不再对自己的数据库提供支持,那么他所准备的相关文档应该能够让其他人轻松地接管后继的设计、开发或管理工作。因此,良好的文档必须包含对于各种列、表、关系和约束的定义,明示每一个元素的使用方式。如果您能适当地包含并说明某些预期值的范例,那就更具有参考价值了。

一些设计师可能会狭隘地将晦涩的文档,作为确保自己工作安全的一种手段,以体现除了自己之外,其他人无法理解目标数据库的稀缺性。这种短见的做法不但很容易被管理层所识破,而且还会给自己若干年后的系统改造、与代码改进工作挖下不少的“坑”。

9.不充分的测试

无论是软件研发也好,还是数据库设计也罢,都离不开严格的测试检验。可不幸的是,测试阶段往往会由于项目截至日期的邻近,而被无情地跳过。当然,这是一种玩火自焚的做法。一些本该在测试阶段被识别和解决的错误和不一致性,往往会给上线后的系统埋下各种隐患。

没有用户愿意使用、也没有管理员愿意维护一个填充bug的数据库。因此,在上线之前所进行的各种深入且广泛的数据库测试,会大大减少部署到生产环境中所可能出现的故障数量和破坏程度。业界普遍认为:好的测试不是要去发现每一个bug,而是帮助您找到并修正大多数潜在的问题。

总结

众所周知,数据库的开发和设计是任何数据密集型项目的核心,它与各种业务应用都息息相关。因此,本文所列出的九种设计中的常见错误,都会在项目的推进和系统的运行中,对数据库的后续性能产生严重的影响,进而产生高昂的修复成本。因此,我们应当在设计的一开始就尽量避开这些坑点,以构建出真正适合项目预期的数据库。

原文标题:9 of the Most Common Mistakes in Database Design,作者:Mokhtar Ebrahim