数据库设计的过程是将数据库系统与现实世界密切地、有机地、协调一致地结合起来的过程。数据库的设计质量与设计者的知识、经验和水平密切相关。作为数据库应用系统的重要组成部分,数据库设计的成败往往直接关系到整个应用系统的成败。以数据库为基础的数据库应用系统与其他计算机应用系统相比往往具有数据量庞大、数据保存时间长、数据关联复杂、用户要求多样化等特点。
数据库设计过程一般包括:需求分析、概念设计、逻辑设计、物理设计、应用开发(系统实施)、系统维护。
数据库设计中面临的主要困难和问题有:
(1)同时具备数据库知识与应用业务知识的人很少。懂得计算机与数据库的人一般都缺乏应用业务知识和实际经验,而熟悉应用业务的人又往往不懂计算机和数据库。
(2)项目初期往往不能确定应用业务的数据库系统的目标。
(3)缺乏完善的设计工具和设计方法。
(4)需求的不确定性。用户总是在系统开发过程中不断提出新要求,甚至在数据库建立之后还要求修改数据库结构或增加新的应用。
(5)应用业务系统千差万别,很难找到一种适合所有业务的工具和方法,这就增加了研究数据库自动生成工具的难度。因此,研制适合一切应用业务的全自动数据库生成工具是不可能的。
数据库设计的关键是确保数据效率、可用性和安全性。
因此,规范化数据库对简化开发和始终如一的高性能至关重要。规范化存在很多层次,设计过程中另一个极端是极容易造成过度规范化的数据库设计。良好的规范化平衡了记录插入、更新、查询和删除的需求。采用最广泛的最佳实践是,数据库必须至少规范化到第三范式(Third Normal Form,简称 3NF)。
冗余表和字段对数据库设计人员和管理员来说是一个噩梦。它们需要占用系统资源才能保持安全、更新和备份。当我们讨论十多个记录时,冗余记录也许看起来不多。但是,在大型数据库中,冗余字段可以是数千个或数百万个,计算资源开销很大。它们不必要地增加了数据库的规模,降低了效率,增加了数据崩溃的风险。
当然,有时候冗余也许是必要的,但是,这应该是例外,而不是规则。即使允许冗余,也应当清楚地记录理由,以确保将来该理由不再有效时,数据库管理员可以删除冗余。
关系数据库的构建思想:数据库中的每个对象只代表一个事物。任何数据集所代表的事物都不应该含糊不清。通过查看主键、表名、列名和关系,我们应该可以快速解读数据集的意义。尽管如此,对于数据库设计,一种挥之不去的误解是,表越多,数据库就越混乱越复杂。
通常,把几张表压缩到一张表中就是简化设计的原理。这听上去是个好主意,但是,通常得到的是效率低下且难以操作的数据库。SQL 代码将变得很长,难以阅读,也不自然。这将把两种截然不同的东西混在一起。乍一看,域表看起来像一个抽象的文本容器。从实现的角度来看,这是正确的,但是,这不是设计数据库的最好方法。
作为规范化过程的一部分,隔离和分解数据最终形成每一行只代表一个事物。每个域表与所有其他域表都不同。
多个域表的最终结果是:
使用在查询中的数据变得更容易。
可以更自然地用外键约束来验证数据,这对单域表设计来说是不切实际的。我们可以用单域表来做,但是每张表所需的键将使维护变成雷区。
无论何时我们需要添加与某个对象相关的更多数据,该任务就像添加一个或多个列那样简单。
小型域表可以放入硬盘的单个页中,而不像大型域表需要分散在多个硬盘分区中。表存放在单个页中意味着可以用单次硬盘读来完成数据提取。
拥有多个域表并不妨碍我们对所有行使用一个编辑器。域表最有可能拥有相同的底层用法 / 结构。
糟糕的或不一致的命名约定可能是个灾难性的错误。数据库设计人员和开发人员常常把他们的角色完全看作是技术角色。非技术方面(如遵守命名约定)往往被推到优先级列表的较低位置,或者甚至完全被忽略。这应该引起重视。
命名也许是设计人员自行决定的,数据库设计人员应该把他们的工作看作是在他们换了雇主或角色之后还将继续存在的东西。命名约定的目的是,让没有完全参与该项目的人也能比较容易地快速理解表和列的内容。未来的管理员、开发人员或用户不应当必须看完长长的文档才能理解某个表名或列名的意义。表如何命名的具体细节并未得到业界的一致同意。
最重要的是一致性。一旦我们遵循某个特定的风格来命名对象,那么在整个数据库中要坚持使用它。表名必须尽可能是表所代表的内容的完整或简约描述,而列名应该清楚地表明其所代表的信息。对于简单数据库,这并不难。但是,一旦我们构建彼此引用的表,事情就变得复杂了。严格遵循命名约定始终是正确的方向。
这样的约定包括没有列或表名的字符长度限制,以消除使用不易理解或记忆的首字母缩略词的需要。如列名 CUST_DSCR,任何人读到这个名字都将不得不猜测该列包含的内容。CUSTOMER_DESCRIPTION 则是个更好的列名,没有迫使读者展开他们的想象力。
避免冗余:在一张名为“Students(学生)”的表中,我们不必把列命标成 StudentName、StudentAddress 或 StudentGrade,因为 Name、Address 和 Grade 已经足够了。还有,不要使用保留字。用“Index”来标记某列会让人困惑,也会成为错误的来源。可以用一个描述性的前缀,如 StudentIndex。
我们可以仔细地完成世界级数据库设计所要求的所有步骤。但是,如果我们没有对数据库进行严格的测试,那么我们将陷入黑暗之中。不幸的是,当项目延期时,测试阶段受到的影响最大。这是弄巧成拙,因为一个快速通过的数据库会立即被错误及不一致性所困扰,而这些错误应该很容易在测试阶段被识别和解决。
一个满是缺陷的数据库不会让用户和管理员喜欢,即使最终修复了错误,我们也摆脱不了不好的名声。在数据库上线前,进行深入而广泛地测试,这将大大减少部署到生产环境中后产生的故障的数量和规模。良好的测试不会找到每个错误,但是肯定有助于摆脱大多数错误。
数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点。
提倡“三少”原则(一个数据库中表的个数越少越好;一个表中组合主键的字段个数越少越好;?一个表中的字段个数越少越好),数据集成的步骤是将文件系统集成为应用数据库,将应用数据库集成为主题数据库,将主题数据库集成为全局综合数据库。集成的程度越高,数据共享性就越强,信息孤岛现象就越少,整个企业信息系统的全局E—R图中实体的个数、主键的个数、属性的个数就会越少。
提倡“三少”原则的目的,是防止读者利用打补丁技术,不断地对数据库进行增删改,使企业数据库变成了随意设计数据库表的“垃圾堆”,或数据库表的“大杂院”,最后造成数据库中的基本表、代码表、中间表、临时表杂乱无章,不计其数,导致企事业单位的信息系统无法维护而瘫痪。
在给定的系统硬件和系统软件条件下,提高数据库系统的运行效率的办法是:
1) 在数据库物理设计时,降低范式,增加冗余, 少用触发器, 多用存储过程。
2) 当计算非常复杂、而且记录条数非常巨大时(例如一千万条),复杂计算要先在数据库外面,以文件系统方式用C++语言计算处理完成之后,最后才入库追加到表中去。这是电信计费系统设计的经验。
3) 发现某个表的记录太多,例如超过一千万条,则要对该表进行水平分割。水平分割的做法是,以该表主键PK的某个值为界线,将该表的记录水平分割为两个表。若发现某个表的字段太多,例如超过八十个,则垂直分割该表,将原来的一个表分解为两个表。
4) 对数据库管理系统DBMS进行系统优化,即优化各种系统参数,如缓冲区个数。
5) 在使用面向数据的SQL语言进行程序设计时,尽量采取优化算法。
总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化,这三个层次上同时下功夫。
结论:
数据库开发和设计首先需要正确理解数据的用途,规范化数据库的设计,充分考虑到数据的冗余记录,建立合理的库表索引,避免糟糕的或不一致的命名约定以及糟糕的文档说明,充分的进行数据库表的测试。
数据库开发和设计是任何数据密集型项目的核心,这些项目几乎包含了所有业务应用程序。因此,设计过程应该始终在此上下文中进行审查。本文中列出的设计错误一开始会被看作是小而不起眼的问题。然而,最终,它们会极大地降低数据库性能并且修复成本高昂。要从一开始就正确地做事,增加构建非常适合其预期目的数据库的几率。
本次就说到这里,主要要求在数据库设计中需要注意范式和反范式、基础规范、命名规范、表设计规范、索引相关的问题点,高性能数据库表设计实践办法。其他方面的以后有机会再详细讨论。