数据库设计规范

上传人:无*** 文档编号:164535663 上传时间:2022-10-25 格式:DOCX 页数:32 大小:808.07KB
返回 下载 相关 举报
数据库设计规范_第1页
第1页 / 共32页
数据库设计规范_第2页
第2页 / 共32页
数据库设计规范_第3页
第3页 / 共32页
点击查看更多>>
资源描述
数据库设计规范1.简介数据库设计是指对一个给定的应用环境,构造最优的数据库模式,建立数据库及其他应用系统,使之能有效地存储数据,满足各种用户的需求。数据库设计过程中命名规范很是重要,命名规范合理的设计能够省去开发人员很多时间去区别数据库实体。最近也因为工作需要所以整理出了这个word文档,望大家指正。2数据库设计数据库规划需求分析数据库设计应用程序设计实现测试运行于维护2.1数据库规划定义数据库应用系统的主要目标,定义系统特定任务,包括工作量的估计、使用资源、和需求经费,定义系统的范围以及边界。2.2需求分析2.1.1需求分析步骤与成果涉及人员:用户和分析人员任务:对现实世界要处理的对象进行详细的调查,收集基础数据及处理方法,在用户调查的基础上通过分析,逐步明确用户对系统的需求,包括信息的要求及处理的要求。方法与步骤:1.通过与用户的调查,对用户的信息需求进行收集。2.在收集数据的同时,设计人员要对其进行加工和整理,以数据字典和数据流图的形式描述出来,并以设计人员的角度向用户讲述信息,根据用户的反馈加以修改并确定(该过程是反复的过程)成果:数据流图,数据字典,各种说明性表格,统计输出表以及系统功能结构图。2.1.2数据流图基本元素与数据流图外部实体:存在于软件系统之外的人员或组织(正方形或立方体表示)。加工:数据处理,表示输入数据在此进行变换,产生输出数据(圆角巨型或圆形表示)。数据流:表示流动着的数据(箭头线表示)。数据存储:用来表示要存储的数据(开门矩形或两条平行横线表示)。订单处理系统顶层流程图:0层数据流图:2.3数据库设计2.3.1概念结构设计 对事务加以抽象以E-R图的形式描述出来 E-R图(实体联系图):包括实体,联系,属性实体:现实中的事物例如,学生,老师联系:两个实体之间的关系,1:1、1:N、M:N三种关系属性:实体所具有的属性,例如 学生的学号、姓名、性别等例如:一个学生属于一个班级,一个班级拥有多名学生,E-R图如下网上购物系统E-R图,该系统数据之间存在下列约束1. 一个客户(编号唯一)可以拥有多个订单,每个订单仅属于一个客户。2. 一个订单(编号唯一)可以包含多个订购细目,每个订购细目只属于一个订单。3. 一个商品可以出现多个订购细目中,一个订购细目只包含多个商品。4. 一个商品类别可以包含多种商品,一种商品只属于一个商品类别。图2.22.3.2逻辑结构设计2.3.2.1E-R图转换成关系模式 将E-R图转换成关系模式将每个实体转换成一个关系模式,实体的属性即关系模式的属性,实体的标识即关系模式的键。 根据规则合并E-R图中的1:1,1:N,M:N之间的联系1. 若实体的联系是(1:1),则可以将两个实体转换成两个关系模式,任意一个关系模式的属性中加入另一个关系模式的主键(作为外键)和联系自身的属性2. 若实体间的联系是一对多(1:n),则将n端的实体类型转换成关系模式中加入1端实体类型的主键(作为外键)和联系类型的属性。3. 若实体间的联系是多对多(m:n),则将联系类型也转换成关系模式,其属性为2实体类型的主键(作为外键)加上联系类型自身的属性,而该关系模式的主键为2端实体主键的组合。4. 若关系模式是1:1:1的关系,转换原则同1:15. 若关系模式是1:1:n的联系,转换原则同1:n6. 若关系模式是1:n:m的联系,则可以将联系类型也转换成关系模式,其属性为m端和n端实体类型的主键(作为外键)加上联系类型自身的属性,而关系模式的主键为n和m端实体主键的组合7. 若关系模式是n:m:p的联系,转换规则同m:n根据E-R图实体之间的联系可以转换成以下关系模式:客户(客户编号,姓名,电话,E-mail)。关系的主键:客户编号;外键:无订单(订单编号,订购时间,客户编号)。关系的主键:订单编号;外键:客户编号订购细目(订购明细编号,订购数量,支付金额,订单编号)。关系主键:订购明细编号;外键:订单编号。出现(订购明细编号,商品编号,类型)。关系的主键:订购明细编号,商品编号;外键:订购明细编号,商品编号。商品:(商品编号,商品名称,单价,生产日期,商品类别号,商品类别名)。关系的主键:商品编号;外键:无在关系模式设计中可能会出现以下几个问题:数据冗余、数据修改不一致、数据插入异常、数据删除异常,所以提出范式的要求,目的就是最低限度地冗余,避免插入、删除、修改异常。2.3.2.2范式主属性:包含键的所有属性。 关系模式要求达到4NF (减少冗余,消除操作异常)第一范式(1NF):若关系模式R的每一个分量是不可分的数据项,则关系模式属于第一范式。即每个属性都是不可拆分的.第二范式(2NF):R属于1NF,且每一个非主属性完全依赖于键(没有部分依赖),则R属于2NF例如:选课关系(学号,课程号,成绩,学分)该关系的主键是(学号,课程号),但是课程号学分,所以学分属性部分依赖于主键,即关系部满足第二范式,可以拆分为(学号,课程号,成绩),(课程号,学分)两个关系第三范式(3NF):R属于2NF,且每个非主属性即不部分依赖于码,也不传递依赖于码例如:学生关系(学号,姓名,所属系,系地址)该关系的主键是:学号学号所属系,所属系学号,所属系系地址;根据函数的依赖公理,系地址传递函数依赖于学号,即关系不满足第三范式,可以拆分关系为(学号,姓名,所属系),(所属系,系地址)如果不拆分会存在数据修改异常,比如该学生的换了系,修改了所属系,但是系地址没有修改,这样就造成了修改异常BCNF:R属于3NF,且不存在主属性对码的部分和传递函数依赖例如:关系R(零件号,零件名,厂商名),如果设定每种零件号只有一个零件名,但不同的的零件号可以有相同的零件名,每种零件可以有多个厂商生产,但每家厂商生产的零件应有不同的零件名。这样可以得到:零件号零件名,(厂商名,零件名)零件号所以主属性包括(零件号,厂商名,零件名),但是“零件名”传递依赖于码“厂商名,零件名”,所以关系R不满足BCNF,当一个零件由多个生产厂商生产时,由于零件号只有一个而零件名根据厂商不同而又多个,零件名与零件号之间的联系将多次重复,带来数据冗余和操作异常现象可以将关系分解为(零件号,厂商名),(零件号,零件名)4NF:关系模式R属于1NF,若对于R的每个非平凡多值依赖XY且Y不包含于X时,X必含码,则R属于4NF5NF:对关系进行投影,消除关系中不是由候选码所蕴含的连接依赖对于上面的商品关系,由于关系的主键是商品编号,而商品类别号商品类别名所以商品关系部满足第三范式,非主属性商品类别名传递依赖于商品编号,会存在数据冗余,数据修改异常问题。将商品关系分解为:商品(商品编号,商品名称,单价,生产日期,商品类别号)商品类别(商品类别号,商品类别名)2.3.3物理结构设计为一个给定的逻辑数据模型设计一个最合适应用要求的物理结构的过程 数据库的建立 数据表的建立 索引的建立 视图的建立 触发器的建立 存储过程设计 用户自定义函数设计 对关系模式的数据项加以约束,如检查约束、主键约束、参照完整性约束以保证数据正确性2.4应用程序设计采用高级语言以结构化设计方法或面向对象方法进行设计2.5系统实现3.优化策略3.1.查询优化策略1. 尽可能地减少多表查询或建立物化视图2. 只检索需要的列3. 用带IN的条件字句等级替换or字句4. 经常提交COMMIT,以尽早释放锁3.2表设计1.如果频繁地访问涉及的是对两个相关的表进行连接操作,则考虑将其合并2.如果频繁地访问只是在表中的某一部分字段上进行,则考虑分解表,将该部分单独作为一个表3.对于很少更新的表,引入物化视图4. 当系统中有一些少量的,重复出现的值时,使用字典表来节约存储空间和优化查询。如地区、系统中用户类型的代号等。这类值不会在程序的运行期变化,但是需要存储在数据库中。就地区而言,如果我们要查询某个地区的记录,则数据库需要通过字符串匹配的方式来查询;如果将地区改为一个地区的代号保存在表中,查询时通过地区的代号来查询,则查询的效率将大大提高。程序中宜大量的使用字典表来表示这类值。字典表中保存这类值的代号和实体的集合,以外键的方式关联到使用这类值的表中。然而,在编码阶段,程序员并不使用字典表,因为首先查询字典表中实体的代号,违背了提高查询效率的初衷。程序员在数据字典的帮助下,直接使用代号来代表实体,从而提高效率。虽然字典表在实际上并不使用,但是仍应该保留在数据库中(起码是在开发期内保留)。字典表作为另一种形式上的“数据字典文档”出现,以说明数据库中哪些表的哪些字段是使用了字典表的。为了提高数据库的数据完整性,在开发阶段可以保留完整的字典表和普通表的外键约束。但是在数据库的运行阶段,应该将普通表和字典表的外键删除,以提高运行效率,特别是某些表使用了很多字典表的情况。案例:某数据库中有百万条用户信息,应用系统中常常需要按照地区要查询用户的信息。用户信息表以前是按照具体的地区名称来保存的,现在将具体的名称改为字典表中的地区代号,查询效率大大提高。3.3索引1. 如果查询是瓶颈,则在关系上建立适当的索引;通常,作为查询条件的属性上建立索引可以提高查询效率。2. 如果更新是瓶颈,因为每次更新都会重建表上的索引,引起效率降低,则考虑删除某些索引。3. 选择适当索引,如果经常使用范围查询,则B树索引比散列索引更高效4. 将有利于大多数查询和更新的索引设为聚集性索引。3.4提高IO效率1. 索引文件和数据文件分开存储,事务日志文件存储在高速设备上2. 经常修改数据文件和索引文件的页面大小3. 定期对数据进行排序4. 增加必要的索引项4.数据库命名规范4.1数据库对象对象前缀数据库无表无视图VI索引IX存储过程SP函数FN触发器TR自定义数据类型udDefaultDF主键pk外键FKruleru序列SqUNIQUEuq数据库对象采用26个英文字母(区分大小写)和09这十个自然数,加上下划线_组成,共63个字符。不能出现其他字符(注释除外)。同一个数据库中这些对象名都是不能重复C CHECK_CONSTRAINTD DEFAULT_CONSTRAINTF FOREIGN_KEY_CONSTRAINTIT INTERNAL_TABLEP SQL_STORED_PROCEDUREPK PRIMARY_KEY_CONSTRAINTS SYSTEM_TABLESQ SERVICE_QUEUETR SQL_TRIGGERU USER_TABLEUQ UNIQUE_CONSTRAINTV VIEW4.2命名规范规定1.表名使用单数名例如:对存储客人信息的表(Customer)不使用Customers2.避免无谓的表格后缀1、 表是用来存储数据信息的,表是行的集合。那么如果表名已经能够很好地说明其包含的数据信息,就不需要再添加体现上面两点的后缀了。2、 GuestInfo(存储客户信息)应写成Guest,FlightList(存储航班信息的表)应写成Flight3.所有表示时间的字段,统一以 Date 来作为结尾(而不是有的使用Date,有的使用Time)以大家都熟悉的论坛来说,需要记录会员最后一次登录的时间,这时候一般人都会把这个字段命名为LoginTime 或者 LoginDate。这时候,已经产生了一个歧义;如果仅看表的字段名称,不去看表的内容,很容易将LoginTime理解成登录的次数,因为,Time还有一个很常用的意思,就是次数4.所有表示数目的字段,都应该以Count作为结尾5.所有代表链接的字段,均为Url结尾6.所有名称的字符范围为:A-Z, a-z, 0-9 和_(下划线)。不允许使用其他字符作为名称。7.采用英文单词或英文短语(包括缩写)作为名称,不能使用无意义的字符或汉语拼音。8.名称应该清晰明了,能够准确表达事物的含义,最好可读,遵循“见名知意”的原则。4.3数据库命名规范数据库名称不需要简写,根据实际意义来命名。例如:ReportServer数据库名:ReportServer逻辑数据名:ReportServer;逻辑日志名:ReportServer_log物理数据名:ReportServer.mdf;物理日志名:ReportServer_log.LDFCREATE DATABASE ReportServer ON PRIMARY( NAME = NReportServer, FILENAME = ND:Microsoft SQL ServerMSSQL10.MSSQLSERVERMSSQLuseDataReportServer.mdf , SIZE = 3328KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )LOG ON( NAME = NReportServer_log, FILENAME = ND:Microsoft SQL ServerMSSQL10.MSSQLSERVERMSSQLuseDataReportServer_log.LDF , SIZE = 6400KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)GO注意:避免所有数据库的逻辑名称使用相同的名称。4.4表设计命名规范注意字段名不能使用保留关键字:如action,avg等1、不使用tab或tbl作为表前缀(本来就是一个表,为什么还要说明)2、表名以代表表内的内容的一个和多个名词组成,以下划线分隔,每个名词的第一个字母大写,例如:User、UserLogin,UserGroupRelation等3、使用表的内容分类作为表名的前缀:如,与用户信息相关的表使用前缀User,与内容相关的信息使用前缀Content。4、表的前缀以后,是表的具体内容的描述。如:用户登录信息的表名为:UserLogin,用户在论坛中的信息的表名为:UserBBSInfo5、一些作为多对多连接的表,可以使用两个表的前缀作为表名:如:用户登录表UserLogin,用户分组表GroupInfo,这两个表建立多对多关系的表名为:UserGroupRelation4.4.1字段命名规范1. 字段名不要存在无用前缀,例如表WeiXinConfig,既然我已经知道这张表是关于微信的表,里面的名称字段可以可以使用Name,不需要添加无用的前缀类似WeiXinName,WeiXinGuanZhuMsg,WeiXinUpImgMsg等2. 字段使用实际英文翻译作为命名字段,见名知意,不要使用让人看了半天都不知道是啥意思的字段(类似:lev1,lev2)4.5存储过程命名存储过程名=SP_+表名+操作名字操作名字=insert|delete|update|calculate|confirm例如:SP_community_update4.5.1只允许应用程序通过存储过程访问数据库只允许应用程序通过存储过程访问数据库,而不允许直接在代码中写SQL语句访问数据库。在数据库开发项目中,大量使用存储过程有很多的好处,首先看微软提供信息:使用 SQL Server 中的存储过程而不使用存储在客户计算机本地的 Transact-SQL 程序的优势有:允许模块化程序设计:只需创建过程一次并将其存储在数据库中,以后即可在程序中调用该过程任意次。存储过程可由在数据库编程方面有专长的人员创建,并可独立于程序源代码而单独修改。允许更快执行:如果某操作需要大量 Transact-SQL 代码或需重复执行,存储过程将比 Transact-SQL 批代码的执行要快。将在创建存储过程时对其进行分析和优化,并可在首次执行该过程后使用该过程的内存中版本。每次运行 Transact-SQL 语句时,都要从客户端重复发送,并且在 SQL Server 每次执行这些语句时,都要对其进行编译和优化。减少网络流量:一个需要数百行 Transact-SQL 代码的操作由一条执行过程代码的单独语句就可实现,而不需要在网络中发送数百行代码。可作为安全机制使用:即使对于没有直接执行存储过程中语句的权限的用户,也可授予他们执行该存储过程的权限。除此以外,使用存储过程的好处还有:1、 在逻辑上,存储过程将应用程序层和数据库物理结构分离开来。存储过程形成了一个应用程序和数据库之间的接口。这样的接口抽象了复杂的数据库结构,符合极限编程中“基于接口编程”的思想。2、 将主要的业务逻辑封装在存储过程中,能够避免在应用程序层写大量的代码(在应用程序中通过字符串插入太长的SQL语句影响效率,而且维护困难)。有助于提高开发效率,并且直接在查询分析器中调试存储过程,能够更早的发现系统中的逻辑问题,从而提高代码的质量。3、 在网站一类的应用系统中,SQL注入式漏洞一直是难以完全杜绝的漏洞。如果只通过存储过程来访问数据库,能够大大减少这类安全性问题。(因此,就算是简单的只有一句的SQL语句,也应该写成存储过程。)4、 由于采用存储过程,应用程序的层面可以不关心具体的数据库结构,而只关心存储过程的接口调用。因此,在以下一些情况,存储过程的优势非常明显:需求变更,表的结构必须要改变。使用存储过程,只要参数不变,我们就只需要修改相应的存储过程,而不需要修改应用程序的代码。这样的设计将减小需求变更对项目的影响。为提高效率,使部分字段冗余:一些经常性访问的字段,我们可以在相关的表中进行冗余存储。这样既提高了效率,又通过存储过程屏蔽了冗余细节。为提高效率,使用冗余表(拆分表):一些大的表,为了提高查询效率,可能需要将记录分别保存到多个表中去。使用存储过程,有存储过程来决定从哪些拆分的表中获取或插入数据。这样提高了效率,又不必在应用程序层面关心具体的拆分规则。5、 使用存储过程,便于在项目后期或者运行中集中优化系统性能。在项目开发过程中,由于各种原因,往往无法编写高效的代码,这个问题常常在项目后期或者在运行期体现出来。通过存储过程来封装对数据库的访问,可以在项目集成以后,通过试运行观察系统的运行效率,从而很容易找出系统的瓶颈,并能够通过优化存储过程的代码来提高系统的运行效率。这样的优化,比在运用程序中优化更有效,更容易。同时,过多的使用存储过程,也存在以下一些疑虑:问题一:存储过程编译后,将作为数据库的全局对象保存,太多的存储过程将占用大量的数据库服务器的内存。问题二:在存储过程中实现大量的逻辑,将使大量的运算在数据库服务器上完成,而不是在应用服务器上完成。当访问量很大的时候,会大大消耗数据库服务器的CPU占用率。在此还存在这个一个案例:有一个访问量巨大的网站,有多台WEB服务器构成一个负载均衡的服务器群集,但是只有一台中心的数据库服务器。当访问量持续增加的时候,接入更多的WEB服务器来满足高并发量的访问;但是数据库服务器却没办法一直增加。因此,就需要尽量在WEB服务器上完成业务逻辑,尽量避免消耗数据库服务器的资源。对于这两个担心,我的想法是:问题一的解决:存储过程是经过编译后的SQL语句,在内存中是二进制的代码,并不会消耗太多内存。并且,存储过程比起直接使用SQL语句来说,效率大大提高。换个角度来说,这是一个“以空间换时间”的方案,多消耗一点内存来换取效率的提高,是值得的。问题二的解决:首先,在实现业务逻辑的问题上,在存储过程中实现比在应用程序中实现更容易;其次,从开发效率上,存储过程的开发比应用程序更简单(就完成相同逻辑而言)。在高访问量的系统中,应用服务器和数据库服务器的资源分配的问题,应该从成本的角度来开率:软件开发中的成本,人工支出的费用远远高于硬件支出的成本。我们可以很容易花钱购买更好的服务器,但是很难花钱让开发人员使程序有大幅度的提高。使用存储过程来封装业务逻辑,首先节省的是大量的开发时间和调试时间,并能够大大提高代码的质量。因此,从成本来说,应该使用存储过程。对于大访问量的情况,最简单的办法是投入更多的硬件成本:更快的硬盘,更大的内存和更多的CPU,还有更好的网卡等等。其次,在应用程序的层面,可以大量的使用静态文件缓存的办法来减轻数据库的压力。如:不经常变化的信息,可以从数据库服务器中读取,保存为应用服务器上的XML静态文件等。实在不行的话,应该在系统设计之初,考虑可能的访问量,将系统设计成分布式的。这样就能从根本上解决大访问量的问题。4.5.2命名规范1、存储过程的前缀和表名的前缀类似:把一系列表看成一个对象,字段为对象的属性,存储过程则为访问对象的方法。如:添加用户的存储过程取名为:User_AddUser2、存储过程使用模块的前缀来命名。如,用户管理的存储过程使用前缀user_。3、存储过程的前缀之后,是动词+名词形式的存储过程名(也可以是动词短语)。4.5.3存储过程的参数命名1、参数名采用匈牙利命名法,使用类型的前缀2、每个存储过程都有:errno int和errmsg varchar(255)两个输出参数。应用程序中可以根据这两个参数得到存储过程执行的情况。(这两个参数使用默认值,可以忽略)errno为整型的错误信息代码,执行成功返回0。Errno的值的具体含义通过errmsg参数说明,或者通过代码中的注释或文档。Errmsg为错误信息的字符串描述,这个参数主要用于调试期作为说明,避免在应用程序中使用该值。同时,要注意英文版系统和中文版系统中,信息的语言选择对程序的影响。4.5.4存储过程返回的记录集1、存储过程的输出记录集:为程序的结构清晰,存储过程最好只返回一个记录集。但在某些为了提高性能的场合,还是可以输出多个记录集2、记录集中,每个输出的字段最后都指定字段的别名,以面真实的字段名信息流失到客户端,从而加大黑客找到系统漏洞的可能。4.5.5格式约定1、 所有SQL关键字大写2、 使用良好的变量命名规范3、 保持良好的结构,包括空行、缩进和空格等。4、 块状的语句,一定要写上BEGINEND5、 在每个存储过程的开头加上详细的注释:包括存储过程名称、参数说明、功能说明、返回数据集说明、以及作者和版权声明。6、 每个存储过程内的代码前后必须加上SET NOCOUNT ON 和SET NOCOUNT OFF。7、 存储过程格式的示例如下:CREATE PROCEDURE SP_User_update(Options VarChar(100),strUserName varchar(20),strPwd varchar(50),errno int = 0 OUTPUT,errmsg varchar(255)=NULL OUTPUT)ASBEGINIF Options=UP1BEGINSET NOCOUNT ON/*以下是存储过程的代码*/SET NOCOUNT OFFENDIF Options=UP2BEGINSET NOCOUNT ON/*以下是存储过程的代码*/SET NOCOUNT OFFENDEND4.6视图命名一个数据库中的视图名不能重复视图名=VI(前缀)+表名.表名+描述4.7主键命名一个数据库中的主键名不能重复主键名=PK_(前缀)+表名例如:pk_Community4.8外键命名一个数据库中的外键名不能重复外键名=FK_(前缀)+主表名+从表名+字段名考虑这样一个关系,表Hotel,字段Id, Name, CityId。表City,字段Id,Name。因为一个城市可能有好多家酒店,所以是一个一对多的关系,City是主表(1方),Hotel是从表(多方)。在Hotel表中,CityId是做为外键使用。在实现外键的时候我们可以这样写:ALTER TABLE HotelInfoADD CONSTRAINT FK_Hotel_City_Cityid FOREIGN KEY (CityID) REFERENCES City(ID)4.9触发器命名1. 前缀(tr),描述了数据库对象的类型。2. 基本部分,描述触发器所加的表。3. 后缀(_I、_U、_D),显示了修改语句(Insert, Update及Delete)触发器名=TR_(前缀)+表名+ _I、_U、_D+字段描述例如:TR _Communtiy_u_name(对表community的字段name进行更新)4.10 default约束使用格式如:DF_表名_列名例如:DF _Community_Age4.11CHECK 约束格式:CK_表名_列名例如:CK_Community_Number4.12UNIQUE约束格式:uq_表名_列名例如:uq_Community_Name4.13字段命名规范1、字段不使用任何前缀(表名代表了一个名称空间,字段前面再加前缀显得罗嗦)2、字典名也避免采用过于普遍过于简单的名称:例如,用户表中,用户名的字段为UserName比Name更好。3、布尔型的字段,以一些助动词开头,更加直接生动:如,用户是否有留言HasMessage,用户是否通过检查IsChecked等。4、字段名为英文短语、形容词+名词或助动词+动词时态的形式表示,大小写混合,遵循“见名知意”的原则。4.14 SQL语句规范1、不允许写SELECT * FROM ,必须指明需要读取的具体字段。2、不允许在应用程序代码中直接写SQL语句访问数据库。3、避免在一行内写太长的SQL语句,在SQL关键字的地方将SQL语句分成多行会更加清晰。如:SELECT UserID,UserName,UserPwd FROM User_Login WHERE AreaID=20修改成:SELECT UserID,UserName,UserPwdFROM User_LoginWHERE AreaID=20更加直观4、在一些块形式的SQL语句中,就算只有一行代码,也要加上BEGINEND块。如:IF EXISTS()SET nVar = 100应该写成:IF EXISTS()BEGINSET nVar = 100END5、SQL批处理语句的空行和缩进与一般的结构化程序语言一致,应该保持良好的代码格式。6、所有的SQL关键字大写4.15游标使用约定1、 若无必要,不要使用游标2、 包含游标的存储过程,必须对性能进行认真测试。4.16索引命名规范对于数据库的维护建索引是很平常的事情,但是如果没有一个规范化的命名,我们对于一个表的诸多索引可能需要花上一段时间的了解。1. 如果表中存在主键默认情况下,表的聚集性索引也就是主键列,主键的命名前面已经有提到过,索引名也跟主键名一样,(Pk_表名)2. 对于表上的非聚集索引,建议使用(IX0_表名,IX1_表名).,这样下去,这样也很清晰地表达了索引,对于很多命名文章上提到的需要详细表达出具体的列,我个人觉得没有必要,首先聚集索引经常涉及多列,很难罗列出所有列;还有影响美观当你执行SELECT NAME FROM SYS.COLUMNS 查询索引时,你根据NAME名很快就知道索引来自那张表,是否是非聚集索引,而不用根据OBJECTID列去跟对象表关联。4.17函数命名规范函数命名分两类:1.针对对象的函数,2.用作辅助功能操作的函数(不针对具体的数据库对象)1. 第一类命名:FN_+User+_+对象名 例如:FN_User_Student(对于Student进行操作函数)2. 第二类命名:FN_具体函数解释 例如:FN_Spit(对字段进行拆分函数)简介在您开始阅读这篇文章之前,我得明确地告诉您,我并不是一个数据库设计领域的大师。以下列出的 11 点是我对自己在平时项目实践和阅读中学习到的经验总结出来的个人见解。我个人认为它们对我的数据库设计提供了很大的帮助。实属一家之言,欢迎拍砖 : )我之所以写下这篇这么完整的文章是因为,很多开发者一参与到数据库设计,就会很自然地把 “三范式” 当作银弹一样来使用。他们往往认为遵循这个规范就是数据库设计的唯一标准。由于这种心态,他们往往尽管一路碰壁也会坚持把项目做下去。如果你对 “三范式” 不清楚,请点击这里(FQ)一步一步的了解什么是“三范式”。大家都说标准规范是重要的指导方针并且也这么做着,但是把它当作石头上的一块标记来记着(死记硬背)还是会带来麻烦的。以下 11 点是我在数据库设计时最优先考虑的规则。规则 1:弄清楚将要开发的应用程序是什么性质的(OLTP 还是 OPAP)?当你要开始设计一个数据库的时候,你应该首先要分析出你为之设计的应用程序是什么类型的,它是 “事务处理型”(Transactional) 的还是 “分析型” (Analytical)的?你会发现许多开发人员采用标准化做法去设计数据库,而不考虑目标程序是什么类型的,这样做出来的程序很快就会陷入性能、客户定制化的问题当中。正如前面所说的,这里有两种应用程序类型, “基于事务处理” 和 “基于分析”,下面让我们来了解一下这两种类型究竟说的是什么意思。事务处理型:这种类型的应用程序,你的最终用户更关注数据的增查改删(CRUD,Creating/Reading/Updating/Deleting)。这种类型更加官方的叫法是 “OLTP” 。分析型:这种类型的应用程序,你的最终用户更关注数据分析、报表、趋势预测等等功能。这一类的数据库的 “插入” 和 “更新” 操作相对来说是比较少的。它们主要的目的是更加快速地查询、分析数据。这种类型更加官方的叫法是 “OLAP” 。那么换句话说,如果你认为插入、更新、删除数据这些操作在你的程序中更为突出的话,那就设计一个规范化的表否则的话就去创建一个扁平的、不规范化的数据库结构。以下这个简单的图表显示了像左边 Names 和 Address 这样的简单规范化的表,怎么通过应用不规范化结构来创建一个扁平的表结构。规则 2:将你的数据按照逻辑意义分成不同的块,让事情做起来更简单这个规则其实就是 “三范式” 中的第一范式。违反这条规则的一个标志就是,你的查询使用了很多字符串解析函数例如 substring、charindex 等等。若真如此,那就需要应用这条规则了。比如你看到的下面图片上有一个有学生名字的表,如果你想要查询学生名字中包含“Koirala”,但不包含“Harisingh”的记录,你可以想象一下你将会得到什么样的结果。所以更好的做法是将这个字段拆分为更深层次的逻辑分块,以便我们的表数据写起来更干净,以及优化查询。规则 3:不要过度使用 “规则 2”开发者都是一群很可爱的生物。如果你告诉他们这是一条解决问题的正路,他们就会一直这么做下去,做到过了头导致了一些不必要的后果。这也可以应用于我们刚刚在前面提到的规则2。当你考虑字段分解时,先暂停一下,并且问问你自己是否真的需要这么做。正如所说的,分解应该是要符合逻辑的。例如,你可以看到电话号码这个字段,你很少会把电话号码的 ISD 代码单独分开来操作(除非你的应用程序要求这么做)。所以一个很明智的决定就是让它保持原样,否则这会带来更多的问题。规则 4:把重复、不统一的数据当成你最大的敌人来对待集中那些重复的数据然后重构它们。我个人更加担心的是这些重复数据带来的混乱而不是它们占用了多少磁盘空间。例如下面这个图表,你可以看到 “5th Standard” 和 “Fifth standard” 是一样的意思,它们是重复数据。现在你可能会说是由于那些录入者录入了这些重复的数据或者是差劲的验证程序没有拦住,让这些重复的数据进入到了你的系统。现在,如果你想导出一份将原本在用户眼里十分困惑的数据显示为不同实体数据的报告,该怎么做呢?解决方法之一是将这些数据完整地移到另外一个主表,然后通过外键引用过来。在下面这个图表中你可以看到我们是如何创建一个名为 “Standards”(课程级别) 的主表,然后同样地使用简单的外键连接过去。规则 5:当心被分隔符分割的数据,它们违反了“字段不可再分”前面的规则 2 即“第一范式”说的是避免 “重复组” 。下面这个图表作为其中的一个例子解释了 “重复组”是什么样子的。如果你仔细的观察 syllabus(课程) 这个字段,会发现在这一个字段里实在是填充了太多的数据了。像这些字段就被称为 “重复组” 了。如果我们又得必须使用这些数据,那么这些查询将会十分复杂并且我也怀疑这些查询会有性能问题。这些被塞满了分隔符的数据列需要特别注意,并且一个较好的办法是将这些字段移到另外一个表中,使用外键连接过去,同样地以便于更好的管理。那么,让我们现在就应用规则2(第一范式) “避免重复组” 吧。你可以看到上面这个图表,我创建了一个单独的 syllabus(课程) 表,然后使用 “多对多” 关系将它与 subject(科目) 表关联起来。通过这个方法,主表(student 表)的 syllabus(课程) 字段就不再有重复数据和分隔符了。规则 6:当心那些仅仅部分依赖主键的列留心注意那些仅仅部分依赖主键的列。例如上面这个图表,我们可以看到这个表的主键是 Roll No.+Standard。现在请仔细观察 syllabus 字段,可以看到 syllabus(课程) 字段仅仅关联(依赖) Standard(课程级别) 字段而不是直接地关联(依赖)某个学生(Roll No. 字段)。Syllabus(课程) 字段关联的是学生正在学习的哪个课程级别(Standard 字段)而不是直接关联到学生本身。那如果明天我们要更新教学大纲(课程)的话还要痛苦地为每个同学也修改一下,这明显是不符合逻辑的(不正常的做法)。更有意义的做法是将这些字段从这个表移到另外一个表,然后将它们与 Standard(课程级别)表关联起来。你可以看到我们是如何移动 syllabus(课程)字段并且同样地附上 Standard 表。这条规则只不过是 “三范式” 里的 “第二范式”:“所有字段都必须完整地依赖主键而不是部分依赖”。规则 7:仔细地选择派生列如果你正在开发一个 OLTP 型的应用程序,那强制不去使用派生字段会是一个很好的思路,除非有迫切的性能要求,比如经常需要求和、计算的 OLAP 程序,为了性能,这些派生字段就有必要存在了。通过上面的这个图表,你可以看到 Average 字段是如何依赖 Marks 和 Subjects 字段的。这也是冗余的一种形式。因此对于这样的由其他字段得到的字段,需要思考一下它们是否真的有必要存在。这个规则也被称为 “三范式” 里的第三条:“不应该有依赖于非主键的列” 。 我的个人看法是不要盲目地运用这条规则,应该要看实际情况,冗余数据并不总是坏的。如果冗余数据是计算出来的,看看实际情况再来决定是否应用这第三范式。规则 8:如果性能是关键,不要固执地去避免冗余不要把 “避免冗余” 当作是一条绝对的规则去遵循。如果对性能有迫切的需求,考虑一下打破常规。常规情况下你需要做多个表的连接操作,而在非常规的情况下这样的多表连接是会大大地降低性能的。规则 9:多维数据是各种不同数据的聚合OLAP 项目主要是解决多维数据问题。比如你可以看看下面这个图表,你会想拿到每个国家、每个顾客、每段时期的销售额情况。简单的说你正在看的销售额数据包含了三个维度的交叉。为这种情况做一个实际的设计是一个更好的办法。简单的说,你可以创建一个简单的主要销售表,它包含了销售额字段,通过外键将其他所有不同维度的表连接起来。规则 10:将那些具有“名值表”特点的表统一起来设计很多次我都遇到过这种 “名值表” 。 “名值表” 意味着它有一些键,这些键被其他数据关联着。比如下面这个图表,你可以看到我们有 Currency(货币型)和 Country(国家)这两张表。如果你仔细观察你会发现实际上这些表都只有键和值。对于这种表,创建一个主要的表,通过一个 Type(类型)字段来区分不同的数据将会更有意义。规则 11:无限分级结构的数据,引用自己的主键作为外键我们会经常碰到一些无限父子分级结构的数据(树形结构?)。例如考虑一个多级销售方案的情况,一个销售人员之下可以有多个销售人员。注意到都是 “销售人员” 。也就是说数据本身都是一种。但是层级不同。这时候我们可以引用自己的主键作为外键来表达这种层级关系,从而达成目的。这篇文章的用意不是叫大家不要遵循范式,而是叫大家不要盲目地遵循范式。根据你的项目性质和需要处理的数据类型来做出正确的选择。
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!