如何设计一个优秀的数据库(转)
关于数据库设计的资料很多,大学学位课程里也有专门的故事。但是,正如我们一再强调的,再好的老师也比不上经验的传授。于是我总结了自己这些年走的弯路和经验,在网上找了一些在数据库设计方面颇有造诣的专业人士,教你一些设计数据库的技巧和经验。精选了60个最好的技巧,把这些技巧写进了这篇文章,为了方便索引,分为五个部分:
第1部分——设计数据库之前:该部分列出了12基本技能,包括命名规范和定义业务需求。第2部分-设计数据库表:共有24个指导技巧,涵盖了表中字段的设计和应该避免的常见问题。第3部分-选择钥匙:如何选择钥匙?有10个技巧专门与正确使用系统生成的主键,以及何时以及如何为字段编制索引以获得最佳性能相关。第4部分——确保数据完整性:讨论如何保持数据库清晰和健壮,以及如何最小化有害数据。第5部分——各种技巧:还有许多其他技巧没有包括在以上四部分中,我希望有了它们,您的数据库开发工作会更容易。part 1-在设计数据库之前检查现有环境
设计新的数据库时,不仅要仔细研究业务需求,还要检查现有的系统。大多数数据库项目不是从零开始构建的;通常,组织中总会有现有的系统来满足特定的需求(可能无法实现自动计算)。很明显,现有的系统并不完善,否则你不必构建新的系统。但是对旧制度的学习可以让你发现一些可能被忽略的细微问题。总的来说,对你来说,审视现有的制度是绝对有好处的。
定义标准的对象命名规范
确保为数据库对象定义命名约定。对于数据库表,从项目开始就需要确定表名是复数还是单数形式。此外,应该为表别名定义简单的规则(例如,如果表名是一个单词,别名将取该单词的前四个字母;如果表名是两个单词,取每个单词的前两个字母组成四个字母的别名;如果表名由三个单词组成,您不妨取前两个单词中的一个,然后从最后一个单词中取两个字母,结果仍然是四个字母的别名,以此类推。)对于工作表,表的名称可以以WORK_为前缀,后跟使用该表的应用程序的名称。表中的列[字段]应该采用一套键的设计规则。例如,如果键是数字,可以使用_N作为后缀;如果是字符类型,可以使用_C后缀。列[字段]名称应该使用标准的前缀和后缀。再比如,如果你的表中有很多“money”字段,不妨给每一列[字段]加一个_M后缀。还有,日期列[字段]最好以D_开头。
检查表名、报表名和查询名之间的命名约定。您可能很快会被这些不同的数据库元素的名称弄糊涂。如果坚持统一命名这些数据库的不同组件,至少应该在这些对象名的开头使用Table、Query或Report等前缀来区分。
如果采用Microsoft Access,可以用qry、rpt、tbl、mod等符号来标识对象(如tbl_Employees)。我在处理SQL Server的时候也用tbl来索引表,但是我用sp_company(现在的sp_feft_)来标识存储过程,因为有时候如果找到更好的处理方法,我往往会保存几份。当我实现SQL Server 2000时,我使用udf_(或类似的标记)来标识我编写的函数。
工欲善其事,必先利其器
采用理想的数据库设计工具,如SyBase公司的PowerDesign,支持PB、VB、Delphe等语言,可以通过ODBC连接市面上流行的30多个数据库,包括dBase、FoxPro、VFP、SQL Server等。我以后会重点关注PowerDesign的使用。
获取数据模式资源手册
那些正在寻找示例模式的人可以阅读《数据模式资源手册》一书,该书由Len Silverston、W. H. Inmon和Kent Graziano撰写,是值得拥有的最佳数据建模书籍。这本书包括涵盖各种数据领域的章节,如人、机构和工作效率。
也可以参考其他:萨石轩王梓霏的《数据库系统导论》。
想想未来,但不要忘记过去的教训。
我发现询问用户对未来需求变化的看法非常有用。这样可以达到两个目的:第一,你可以清楚地了解应用程序设计应该在哪些地方更加灵活,如何避免性能瓶颈;其次,你知道当出现一个没有提前确定的需求变化时,用户会和你一样惊讶。
一定要记住过去的经验教训!我们开发者也应该通过分享自己的经历和经验来互相帮助。即使用户认为他们不再需要任何支持,我们也应该对他们进行这方面的教育。我们都曾面临过这样的时刻:“要是我们当初这么做就好了……”。
在物理实践之前设计逻辑。
在深入物理设计之前,要进行逻辑设计。随着大量CASE工具的出现,你的设计可以达到相当高的逻辑水平,你通常可以更好地从整体上理解数据库设计的各个方面。
了解你的业务
不要在你的ER(实体关系)模型中添加甚至一个数据表,直到你100%确定系统从客户的角度满足了它的需求(为什么,你还没有模型?那么请参考提示9)。了解你的业务可以在后期发展阶段节省很多时间。一旦知道了业务需求,就可以自己做很多决策了。
一旦你认为你明确了业务内容,你最好和客户进行一次系统的沟通。使用客户术语,并向他们解释您的想法和听到的内容。同时,系统的关系基数要用可能、意志、必须等词来表示。这样你就可以让你的客户纠正你自己的理解,然后做下一步的ER设计。
创建数据字典和ER图表
一定要花一些时间来创建ER图表和数据字典。它至少应该包含每个字段的数据类型和每个表中的主外键。创建ER图表和数据字典很费时间,但对于其他开发人员来说,理解整个设计是绝对必要的。创建得越早,越有助于避免将来可能出现的混乱,这样任何了解数据库的人都可以清楚地了解如何从数据库中获取数据。
最新文档的重要性怎么强调都不为过,比如ER chart,它对于显示表之间的关系非常有用,而数据字典显示了每个字段的用途以及任何可能的别名。这对于SQL表达式的文档来说是绝对必要的。
创建模式
一个图表胜过千言万语:开发人员不仅要阅读和实现它,还要用它来帮助他们与用户交流。模式有助于提高协作的效率,所以在早期的数据库设计中几乎不可能出现大的问题。图案不必复杂;它甚至可以像在一张纸上写字一样简单。只是为了保证以后逻辑关系能产生效益。
从输入和输出开始
在定义数据库表和字段要求(输入)时,您应该首先检查现有的或设计的报告、查询和视图(输出),以确定哪些表和字段是支持这些输出所必需的。举个简单的例子,如果客户需要一个报表来按邮政编码进行排序、分段和求和,您应该确保它包含一个单独的邮政编码字段,而不是将邮政编码放入地址字段。
报告技巧
要了解用户通常如何上报数据:批处理还是在线提交?时间间隔是每天、每周、每月、每季度还是每年?如有必要,您还可以考虑创建一个汇总表。系统生成的主键很难在报表中管理。当在具有系统生成的主键的表中使用辅键进行搜索时,用户经常会返回大量重复数据。这种检索性能低,容易造成混乱。
了解客户需求
看起来这应该是显而易见的,但需求来自客户(这里是从内部和外部客户的角度)。不要依赖用户写的需求,真正的需求在客户的脑子里。你应该要求客户解释他们的需求,并且随着开发的继续,你应该总是要求客户确保他们的需求仍然在开发的目的中。一个不变的真理是“看到才知道自己想要什么”必然会导致大量的返工,因为数据库不符合客户从来没有写下来的需求标准。更糟糕的是,你对他们需求的解释只属于你,而且可能是完全错误的。
第2部分-设计表和字段以检查更改
当我设计数据库时,我会考虑哪些数据字段将来可能会发生变化。比如姓氏就是这样(注意西方人的姓氏,比如女性婚后随夫姓等。).因此,在构建存储客户信息的系统时,我倾向于将姓氏字段存储在一个单独的数据表中,并添加开始日期和结束日期等字段,以便我可以跟踪此数据项的变化。
使用有意义的字段名
有一次我参与了一个项目的开发,里面有一个继承自其他程序员的程序。程序员喜欢用屏幕上显示的数据指令给字段命名,这还不错,但遗憾的是,她还喜欢用一些奇怪的命名方式,用了匈牙利命名和控制序列号的组合,比如cbo1,txt2,txt2_b等等。
除非您使用的是专用的缩写字段名系统,否则请尽可能清晰地描述这些字段。当然也不要过分,比如customer _ shipping _ address _ street _ line _ 1。虽然很有描述性,但是没人愿意打这么长的名字。具体尺度你自己把握。
使用前缀命名
如果多个表中有很多相同类型的字段(比如FirstName),不妨使用特定表的前缀(比如CusLastName)来帮助识别字段。
及时性数据应包括“最后更新日期/时间”字段。时间戳对于查找数据问题的原因、按日期重新处理/重新加载数据以及清除旧数据特别有用。
标准化和数据驱动
数据的标准化不仅方便自己,也方便别人。例如,如果您的用户界面想要访问外部数据源(文件、XML文档、其他数据库等。),你不妨把对应的连接和路径信息存储在用户界面支持表中。此外,如果用户界面执行工作流(发送邮件、打印信纸、修改记录状态等)等任务。),那么生成工作流的数据也可以存储在数据库中。前期的安排总是需要努力的,但是如果这些流程是数据驱动而不是硬编码的,那么政策的改变和维护就会方便很多。事实上,如果流程是数据驱动的,您可以将相当大的责任放在用户身上,他们将维护自己的工作流程。
标准化不应过度。
对于不熟悉标准化这个词的人来说,标准化可以确保表中的字段是最基本的元素,这种措施有助于消除数据库中的数据冗余。标准化有几种形式,但第三范式(3NF)通常被认为是性能、可伸缩性和数据完整性之间的最佳平衡。简单来说,3NF规定:
表中的每个值只能表示一次。表中的每一行都应该唯一标识(用唯一的键)。依赖于其他键的非键信息不应存储在表中。符合3NF标准的数据库有以下特点:有一组专门存储相关数据的表,通过键连接。例如,存储客户及其相关订单的3NF数据库可能有两个表:customer和order。Order表不包含与订单相关联的客户的任何信息,但是表中将存储一个键值,该键值指向Customer表中包含客户信息的行。
标准化程度也更高,但标准化程度越高就一定更好吗?答案是不一定。事实上,对于一些项目,即使是3NF也可能给数据库带来太多的复杂性。
为了效率,有时候需要不规范表格,例子很多。曾经有一份工作是开发餐饮分析软件,使用非标准化的表格,将查询时间从平均40秒减少到两秒左右。虽然我不得不这么做,但我绝不会把数据表的非标准化当成一种自然而然的设计理念。而具体操作只是一个衍生。所以如果表出了问题,完全有可能重现非标准化的表。
不活动或不活动指示器
添加一个字段来指示记录在业务中是否不再有效是很有用的。无论是客户、员工还是其他任何人,这都有助于在再次运行查询时过滤活动或非活动状态。同时也消除了新用户在采用数据时面临的一些问题。比如有些记录他们可能不再使用,删除了可以起到一定的预防作用。
使用角色实体来定义属于某个类别的列[字段]。
当需要定义属于特定类别或具有特定角色的事物时,可以使用角色实体来创建特定的时间关联,从而实现自文档化。
这里的意思不是让PERSON实体有Title字段,而是说,为什么不用PERSON实体和PERSON_TYPE实体来描述人呢?例如,当John Smith,工程师晋升为John Smith,董事,并最终爬到John Smith,CIO的高位时,您所要做的就是更改两个表PERSON和PERSON_TYPE之间的关系的键值,并添加一个日期/时间字段以了解更改发生的时间。这样,PERSON_TYPE表就包含了所有可能的人员类型,比如助理、工程师、主管、CIO或CEO。
另一种替代方法是更改人员记录以反映新头衔的变化,但无法及时跟踪个人所在位置的具体时间。
使用公共实体命名机构数据。
组织数据最简单的方法是使用常见的名称,如个人、组织、地址和电话。当你组合这些常见的通用名称或创建特定的对应子实体时,你就为自己获得了一个特殊的版本。之所以一开始就采用通用术语,主要是因为所有具体的用户都可以把抽象的东西具体化。
有了这些抽象的表示,你可以在二级logo中使用自己的特殊名称。例如,人可以是雇员、勺子、病人、客户、顾客、卖主或老师。同样,组织也可以是我的公司、我的部门、竞争对手、医院、仓库、政府等。最后,地址可以是具体的地点、位置、家庭、工作、客户、供应商、公司和现场办公室。
使用一般的抽象术语来标识“事物”的类别,可以让你在关联数据以满足业务需求时有很大的灵活性,同时也可以显著减少数据存储所需的冗余。
用户来自世界各地。
在设计具有internet或其他国际特征的数据库时,必须记住大多数国家都有不同的字段格式,如邮政编码,而有些国家(如新西兰)没有邮政编码。
数据复制需要使用单独的数据表。
如果您发现自己在重复输入数据,请创建一个新表和一个新关系。
应该添加到每个表中的三个有用的字段
DRecordCreationDate,在VB中默认为Now(),在SQL Server中默认为GETDATE()sRecordCreator,在SQL Server中默认为not null默认usernrecordversion,是记录的版本标记;准确解释记录中出现空数据或缺失数据的原因很有帮助。对地址和电话号码使用多个字段。
仅仅用一行来描述街道地址是不够的。Address_Line1、Address_Line2和Address_Line3可以提供更大的灵活性。此外,电话号码和电子邮件地址应该有自己的数据表,有自己的类型和标签类别。
小心过度标准化,这可能会导致性能问题。虽然地址和电话列表的分离通常可以达到最好的状态,但如果需要经常访问这类信息,那么存储“首选”信息(如客户等)可能更合适。)在其父表中。非标准化和加速访问之间的折衷是有意义的。
使用多个名称字段
我很惊讶,许多人在数据库中留下一个字段作为姓名。我觉得只有新手开发者才会这么做,但其实这种做法在网上很常见。我建议把姓和名当做两个字段,然后在查询的时候合并。
我经常使用的是在同一个表中创建一个计算列[字段],通过它可以自动连接标准化的字段,这样当数据发生变化时,它也会发生变化。但是,在使用建模软件时,你必须聪明。总之,连接字段可以有效地将用户应用程序与开发人员界面隔离开来。
注意混合大小写的对象名和特殊字符。
过去最让我恼火的一件事就是数据库中有混合的case对象名,比如CustomerData。这个问题存在于对Oracle数据库的访问中。我不喜欢用这种大小写混合的对象命名方式,结果就是要手动改名。你想想,这个数据库/应用能混到采用更强大的数据库的那一天吗?全大写和下划线的名称可读性更好(CUSTOMER_DATA)。永远不要在对象名的字符之间留空格。
小心保留字。
确保您的字段名不与保留字、数据库系统或常用访问方法冲突。例如,在我最近编写的ODBC连接程序中有一个表,其中DESC被用作描述字段名称。后果可想而知!DESC是降序缩写后的保留字。表中的一个SELECT *语句可以使用,但是我得到了很多无用的信息。
保持字段名和类型的一致性。
在为字段命名和指定数据类型时,一定要保持一致。如果一个表中的字段名为“agreement_number”,则不要在另一个表中将名称更改为“ref1”。如果一个表中的数据类型是整数,不要在另一个表中将其更改为字符类型。请记住,在您完成工作后,其他人将使用您的数据库。
仔细选择号码类型。
在SQL中使用smallint和tinyint类型时要特别小心。例如,如果您想查看月总销售额,而您的合计字段类型是smallint,那么如果合计超过32,767美元,您就无法进行计算。
删除标记
在表中包括“删除标记”字段,以便可以将行标记为删除。不要删除关系数据库中的任何一行;最好使用数据清理程序,并小心维护索引的完整性。
避免使用触发器。
触发器的功能通常可以通过其他方式实现。调试程序时,触发器可能会成为干扰。如果你真的需要使用触发器,你最好专注于记录它。
包括版本机制
建议您在数据库中引入版本控制机制,以确定正在使用的数据库的版本。无论如何你必须满足这个要求。随着时间的推移,用户的需求总是会发生变化。您最终可能需要修改数据库结构。虽然您可以通过检查新字段或索引来确定数据库结构的版本,但我发现将版本信息直接存储在数据库中更方便。
为文本字段留出足够的边距。
ID类型的文本字段,如客户ID或订单号,应该设置得比平时大,因为您可能会不好意思在短时间内添加额外的字符。例如,假设您的客户ID长度为10位数字。然后,您应该将数据库表字段的长度设置为12或13个字符。这是浪费空间吗?有点,但没你想的那么多:如果一个字段加长三个字符,有1万条记录,再加上一点索引,只会让整个数据库占用3MB更多的空间。但是,这额外的空间并不需要在未来重建整个数据库来实现数据库规模的增长。最好也是最痛苦的例子就是身份证号码从15位改成18位。
列[字段]的命名技巧
我们发现,如果对每个表的列[字段]名称使用统一的前缀,那么在编写SQL表达式时将会大大简化。这确实有一些缺点,例如破坏了自动表连接工具的功能,这些工具将公共列[字段]名称与一些数据库链接起来,但即使是这些工具有时也会连接错误。举个简单的例子,假设有两个表:
客户和订单。客户表的前缀是cu_,所以表中的子段名如下:cu_name_id,cu_surname,cu_initials,cu_address。订单表的前缀是或_,因此子部分的名称是:
Or_order_id,or_cust_name_id,or_quantity和or_description等。
从数据库中选择所有数据的SQL语句可以写成如下形式:
1Select*FromCustomer,OrderWherecu _ surname = " MYNAME2和Cu _ name _ ID = or _ cust _ name _ ID odor _ quantity = 1如果没有这些前缀,就写成这样(用别名区分):
1Select*FromCustomer,order where customer . surname = " my name ";