是不是赶工的孕妇梦见产检结果不好,后面细节处理不好导致平衡性失调

(window.slotbydup=window.slotbydup || []).push({
id: '2014386',
container: s,
size: '234,60',
display: 'inlay-fix'
&&|&&0次下载&&|&&总52页&&|
您的计算机尚未安装Flash,点击安装&
阅读已结束,如需下载到电脑,请使用积分()
下载:20积分
0人评价308页
0人评价20页
0人评价24页
0人评价1页
0人评价1页
所需积分:(友情提示:大部分文档均可免费预览!下载之前请务必先预览阅读,以免误下载造成积分浪费!)
(多个标签用逗号分隔)
文不对题,内容与标题介绍不符
广告内容或内容过于简单
文档乱码或无法正常显示
文档内容侵权
已存在相同文档
不属于经济管理类文档
源文档损坏或加密
若此文档涉嫌侵害了您的权利,请参照说明。
我要评价:
价格:20积分VIP价:16积分407被浏览17,737分享邀请回答
http://v.youku.com/v_show/id_XMjY3NjYxNTAyOA==.html?spm=a2hzp..0&from=y1.7-2#paction
这里还要提一点,后期数据库表小范围的修改一般是由开发人员发现,比如在开发过程中发现少了一些字段,或局部业务有些问题等等,应该禁止开发人员擅自直接更改数据库,所有更改无论大小必须经过数据库主设计师的审核同意,以避免可能影响到全局的更改出现。数据库的设计工作虽然集中在项目的业务梳理清晰之后、正式开发之前,但相关细枝末节的工作却不止于此,很可能会贯穿于整个项目的起始流程。B.三种关系有人说数据库难以设计,其实难的并不是数据库的设计,而是业务流程的梳理。再复杂的业务,只要理得清,表现在数据库中,无外乎是表与表间的三种关系:一对一(one-to-one)、一对多(one-to-many )以及多对多(many-to-many)。更进一步的,many-to-many实际上就是两个one-to-many。在Java中万事万物皆对象,在关系型数据库中万事万物皆是二维表,而事物之间的联系系就是表与表间的这三种关系。后面还会多次提及,我们的设计原则是尽可能让粒度小、容忍度高,比如在“设计规范”——“字段设置”——“通用字段处理”中有关于日期时间类型设置的说明,要求日期时间类型的字段,尽可能用datetime类型,精确到时分秒,而不要用date类型。表现在这里,处理业务关系时,对于核心业务部分尚不能明确表与表关系的,能一对多就不要一对一,能多对多就不要一对多。这样开发的复杂度会增加,却消除了后面可能的修改扩展的隐患。对于非核心业务也不能明确关系的,可根据实际情况,综合考量开发实现的烦琐程度及未来的可变性再做决定。PD细化了这三种关系的表述,表现在CDM关系中Cardinalities选项卡的Cardinality选项中、表现在PDM引用中Integrity选项卡的Cardinality选项中。Cardinality,基数,在CDM的选项中表示另一方对于当前方的每个实例,可能拥有的实例的最少和最多数;在PDM的选项中表示父表中的每个实例,子表中可能拥有的实例的最少和最多数。比如“病人”与“会诊单”两个实体之间的联系是one-to-many联系,换个方向说“会诊单”和“病人”之间的联系是many-to-one联系。而且一个会诊单必须属于一个病人,并且只能属于一个病人,不能属于零个病人,所以从“会诊单”实体至“病人”实体的基数为“1,1”;从联系的另一方向考虑,一个病人可以拥有多个会诊单,也可以没有任何会诊单,即零个会诊单,所以该方向联系的基数就为“0,n”。CDM中的表示如下图所示:在构建CDM、选择两个实体之间的关系时,这部分会自动赋值的。类似的,一个品牌必需且只能属于一个企业,一个企业却可以有一个或多个品牌,又或者一个也没有。在PDM的选项中表示父表为企业、子表为品牌,父表(企业)中的每个实例,子表(品牌)中可能拥有的实例的最少和最多数。如下图所示:PD的细化在于,one-to-one关系中到底是must have one and only one还是may have at most one,one-to-many关系中到底是must have one or more还是may have one or more。many-to-many关系需要借助中间表实现,分解成两个one-to-many组合,类似的,也可被细分成严格的多对多还是模糊的多对多。可以拿用户和角色的例子说明,严格的多对多是一个用户至少有一个角色、一个角色至少被一个用户拥有,模糊的多对多是一个用户可以没有任何角色、一个角色可以不被任何用户拥有。个人认为对one-to-many和many-to-many两种关系进行细化的意义不大,因为对于one-to-many、many-to-one,无论是否严格,都要在many方加入引用one方主键的外键;而对于many-to-many,无论是否严格,中间表都是必须的。所以对于这两种关系,无论是否为严格的,设计方案是确定的。但对于one-to-one,严格的和非严格关系之间设计上是有区别的。比如订单和取消原因,一个订单可以有一个或零个取消原因(may have at most one ),本来如果是严格的一对一关系,取消原因是可以整合到订单表中的,而无需单建表存储。 再比如班级与班长,一个班级只有一个正班长, 一个班长只在一个班中任职,两边都是must have one and only one,那班长表完全可以省略,而直接在班级表中加入相应描述班长信息的字段即可,比如班长名称、性别等等,又或者直接有个班长的外键字段指向学生表。C.如何设计拿到项目后,完成早期的需求调研,在分析设计的过程中,先考虑的是要实现所需功能、需要的实体有哪些。比如要实现登录功能,那必需要有用户实体。继续扩展思路,登录往往伴随着角色划分,为此要有角色、权限相关的实体。为了记录登录请求,又要有登录日志实体。这些实体表现在数据库即为相应的表,实体确定,同步考虑实体与实体间的关系。一个用户可以有多个角色,一个角色可以被多个用户拥有,所以用户和角色是多对多关系,多对多关系意味着出现中间表。一个用户可以有多条登录日志,一条登录日志有且只能对应一个用户,所以用户和登录日志是一对多的关系,登录日志表中要有外键引用用户表。这就是数据库设计的过程。数据库的设计往往和前端界面的设计并行,前者稍晚于后者,两者的进行伴随在业务梳理的过程中、前期需求确认之后,为确保对需求理解的准确性、设计的准确性,此过程中应该继续和需求提出者保持沟通。如果在设计数据库时不考虑前端界面设计、或者是在设计界面时不考虑数据库设计,且不说两边对业务需求的理解可能有偏差,即便完全没有,最终怕也不能完好无误的进行融合,这也是为什么觉得项目经理、产品经理、技术经理的角色一人扮演要比三人分饰更好的原因。成熟的社会体制下,人与人间的分工应该更加明确,这无可厚非,问题就出在很多公司分工提前明确了,协作体制却不完善。如此这般,做一件事情参与的人越多,不但不会节省工时,反而导致的问题越多,大大降低了工作效率。负责数据库设计工作的人应该是最懂项目、最懂业务需求、最有设计经验的人,此人必须跟踪整个项目的设计开发过程,产品界面的设计、程序的开发都要和其沟通确认方可。项目设计开发实施过程中,很多决定,不是参与决定的人越多越好,而是由一个最懂项目的人决定最好。有时为了某个决定组织集体讨论,最终的决定往往来自于主导讨论者,而非是最懂项目者。做项目和带兵打仗一样,最怕饭桶主导局势。而做为项目主负责人,你可以不是最懂项目的,但一定要清楚的是这个项目安排给谁去懂最合适,他有没有这个能力、是否能听从安排。一旦让他去懂,在项目推进过程中观察他是否能胜任、各子环节最懂的那个人又是谁。明白谁最懂、谁肯听众安排,则把相应部分的决定权交到相应最懂、最听从安排的人手中。而后除非出现特殊情况,自己不要去干涉、也不要让其他人去干涉。D.主设计师原则上讲,百张表内的数据库最好由一人来设计。一百张表,即使每张有一百个字段,总共也不过一万个,如果用工具生成,三五天内足够。当然数据库设计工作的难易并非是由表个数、字段个数决定的,而更多在于业务的复杂程度。表个数、字段个数在一定程度上可以反应出业务的复杂程度,但却非决定性因素。这里讲百张表内的设计工作量并不大,是说业务理清后将设计具体化成CDM、PDM的体力工作。要求由一人来设计是为了确保最终数据库的统一性、完整性、协调性,如果不能保证统一,最终项目的稳定性绝对得不到保障。不仅数据库的设计如此,架构、程序、前端、样式、脚本、UI都一样。在项目设计阶段,通常情况下,局部模块设计的优良并不会提升整个项目的质量,然而局部模块设计出现的问题最终却可能撼动整个项目的稳定。千里之堤毁于蚁穴,务必要确保设计工作的谨慎协调统一。再说大部分企业内部应用系统,项目规模有限,一个人主设计足够。特殊情况下,如果项目大到一定程度,所有数据库设计工作交到一人手上着实过量,不得不安排多人参与其中,那主设计师也必须只有一位,且所有参与人员都要严格遵守相应的数据库设计规范。要利用PD的版本控制功能协调统一,最终由主设计师汇总校验所有人的设计,最终的数据库设计应该看起来像一个人的杰作,这也是程序、脚本、样式、UI设计开发所追求的目标。主设计师汇总校验之后,还应再组织会议对设计成果校验,包括所有参与设计的人员、程序开发人员等,一起讨论。查找可能出现的不合理的地方,比如有部分可能和需求业务不合、可能会影响到开发实现等等。数据库的校验审核工作,参与人员尽可能多点,鼓励提问,有助于查缺补漏,发现问题。E.关于DBA有公司规定所有项目的数据库设计,DBA必须参与,但数据库设计工作重在对业务的把控、了解,其次才是对数据库本身的了解,这两项缺一不可,且前者更为重要。DBA的专业技能或许会更好一点,但是对业务的了解呢?还有公司的运维团队中,DBA会脱离项目实际,设置一些不必要的数据库规范,强加给开发团队。在做项目时,一方面非常讨厌外部强加的规范,另一方面又不停的给自己、给团队设定规范。讨厌外部强加的规范是因为这些规范大都是些PMO指定的人凭空设想出来、脱离项目实际的,这些规范只会给项目带来更多的麻烦。而给自己和团队设定规范,则是为了约束设计和开发行为,确保项目最终实现的合理统一协调,这在后面的“命名规范”——“引言”中还有进一步的说明。大的项目、大的团队可能会有多个专业DBA负责数据库维护工作,但就自己接触,即便公司、团队本身有DBA,绝大部分规模的项目中数据库维护工作还是多由程序开发人员兼顾。再者,真正优秀的DBA少之又少,有时不够专业的DBA过多介入反而会阻碍项目的正常开发。DBA出现的时机应该是在开发人员无法解决数据库出现的问题时,比如当数据量大到一定程度,项目运行缓慢,仅凭程序优化已遇到瓶颈,这时可以向公司申请DBA介入,优化数据库设计、SQL语句等。再比如遇到数据备份问题、出现数据丢失问题等,也可申请DBA协助。如果项目规模大到一定程度,出现性能瓶颈问题是很正常的,这时专业DBA的作用才开始突显,且会在其中扮演一个非常重要的角色。总之,DBA应该是在被需要时出现,而不应该被强制需要。我的项目开发思路非常明确,关于团队,人越少越优秀越好,人员明确分工;关于开发模式,前端、后端、数据库明确分工。在项目规模、工作量允许的范围内人越少越好、涉及合作的部门越少越好,以便统一管理控制,节约沟通协调的成本。开发过程中的规范和约定采用大一统的方式,严格限制脱离中央管控的脚本或代码出现。3、基本原则A.数据编码这里建议将MySQL数据库编码设置为utf8, SQLServer、Oralce可先采用默认设置,有需要则根据实际情况做相应变动。如果是MySQL在安装时就应注意,下图是当前电脑中数据库的编码设置,安装时没有改过,是默认的,所以显示的是latin1。编码问题设置不妥当,数据库导入导出备份很容易出现乱码,尤其是旧版本的MySQL数据库。日常的数据库维护操作推荐使用其官方工具MySQL Workbench,Oracle的话推荐SQL Developer,也是官方工具。如果使用MySQL Workbench创建新的数据库,会要求选择Collation,默认即可。Collation的字面意思是字符序,用于指定数据集如何排序,以及字符串的比对规则。这地方的设置会影响到数据查询时大小写敏感的问题,这里简单一提,具体介绍的会在命名规范中给出。如果是MySQL数据库,表类型统一使用InnoDB。InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。其区别在于MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持及外部键等高级数据库功能。没有进行过额外设置,数据库默认安装的就是InnoDB类型。B.高级功能在本章节的引言中提到过,存储过程、触发器、函数、视图、事件等高级功能的设计规范都未给出详细说明,因为本规范中要求,在当前阶段的所有项目中,禁止使用存储过程、触发器、函数、视图、事件等高级功能,数据库中只有表,数据库只做数据存储、标明业务关系。而具体业务逻辑相关的处理均由程序实现,比如分页、日志记录等等。某些情况下,一些业务逻辑放在数据库中处理比放在程序中处理要简单许多,但这会额外增加数据库的维护工作,从全局来看,也就是增加增个项目的维护工作。尤其是项目要求支持多数据库时,不同数据库存储过程、触发器、函数等的编写方式差异巨大,很难统一控制。业务逻辑下压到数据库的部分越多,这种维护就愈加困难,到一定程度必然要求有专业的DBA配合,额外增加了不必要的麻烦。视图的添加更是没有必要,连接查询可以实现的功能,用视图只会从全局上扰乱原有的数据库表关系,让程序多维护一套查询程序,徒增麻烦,而所得收益完全可由单纯的程序实现。前面已提到所坚持的开发模式,给前端、程序、数据库明确的分工:前端只负责数展示、人机交互,由前端脚本处理展示交互相关的逻辑;后台程序负责桥接前端界面和数据库,处理核心业务逻辑;数据库部分只用来数据存储、标明业务关系。三部分各司其职,不要在数据库中直接处理业务逻辑,不要在后台程序中直接处理前端展示或人机交互的逻辑。当项目庞大到一定程度、业务逻辑复杂到一定程度、数据量并发访问量增加到一定程度,单纯的从程序、前端中优化效果有限,需要多管齐下时,再来动数据库。即便到那时,最好也是在PD中统一设计这些功能,可以自由导入。否则,如果是多数据库支持的项目,每种数据库都得分别手动编写不同的代码,这样配置会很麻烦,也很难统一控制。而对于绝大部分中小型项目,这些麻烦本是没有必要出现的。C.遵守范式目前关系数据库有六种范式:第一范式(1NF)属性不可分。是指在关系模型中,对域添加的一个规范要求,所有的域都应该是原子性的,即数据库表的每一列都是不可分割的原子数据项。第二范式(2NF)在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)第三范式(3NF)在1NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)巴斯-科德范式(BCNF)Boyce-Codd Normal Form(巴斯-科德范式)在1NF基础上,任何非主属性不能对主键子集依赖(在3NF基础上消除对主码子集的依赖)第四范式(4NF),要求把同一表内的多对多关系删除。第五范式(5NF),又称完美范式,从最终结构重新建立原始结构。这些范式仔细讲起来很耗文笔,关于范式的详细介绍可以参考文档末尾的参考文献。在设计数据库时,尽可能做到前四个即可。但范式并非硬性要求,而是设计时尽可能遵守的大原则。对于这些范式也没必要刻意去记,关系型数据库说到底只是二维的行列组合,参与的数据库设计多了,设计理念自然成型,会不自觉的去向这些范式中靠拢,设计过程中可以以此为依据校验自己的设计是否合理,及时修正不当设计。特殊地方,为了操作方便,在不影响核心业务的情况下,允许小范围的不遵守范式。平时的多图片上传功能,可能只设计一个字段存储图片名称,这样字段值中就会包含多个图片的名称,里面用|或其它符号分隔,这样属性值就可分了,也就违反了第一范式——属性不可分;还有地区表中的,地区编码字段也隐含有等级信息;再就是菜单相关表,里面分等级互相引用等等;严格来讲这些都是不符合规范的。在小范围内,不影响到核心业务流程,为了设计开发的方便,允许一些特殊的设计出现。规范是用来约束设计的,约束的目的是为了最终整体设计的合理性、为了最终项目的稳定性,如果这种全局的规范约束在局部影响到开发实现,可以适当调整,但前提是设计者要有足够的经验和能力驾驭住这种不当调整。D.连接查询因为不允许使用视图,所以在表设计时要尽可能的考虑到后面的连接查询,目前所接触项目的数据量都尚在可控范围之内,一般的业务系统,允许三张表以内的连接查询,五张表以内的要限制,超过五张的禁止。禁止使用子查询,子查询转换成关联查询。如果要尽可能避免多表连接查询,那在设计数据库时,有关联关系的地方,一般从表中除了有引用主表主键的外键字段外,还要有一个或多个字段存放主表中的关键信息,比如病人表中有所属医院所属科室主键的外键字段,但还可能会有所属医院名称所属科室名称的字段。因为嫌数据冗余、维护不易,之前自己一般不设计除外键外存放主表信息的其它字段,但这样查询时又会多添好些麻烦。可如果加上这些字段,不单单数据冗余、维护麻烦,也不好保证数据的准确协调统一性。比如如果医院的名称被修改了,那按常理病人表中的医院名称也得做相应的修改才可以,这样,如果医院表被许多表引用,那就得对所有的表执行修改动作,很是麻烦,实现起来也不现实。如果都加上引用约束,依赖数据库自己的关联自动更新,觉得也不是很好,影响程序执行速度且不易维护。可如果是在会诊单表(类似于订单表的功能)中出现类似的情况,就无须有这种顾虑,如果这个会诊单在产生时医院是这个名称,后面名称有了更改,那会诊单中的医院名称还是显示早前的即可,无须做相应更改,这也是符合逻辑的。类似情况经常出现在字典相关信息的存取中,平时只在表中存字典编码,但查询时又往往要求同时提供字典文本,核心业务表中的字典字段往往比较多,暂时没有好的方法一次高效提取完整信息。后面在做类似设计时,核心业务表,字典字段比较多的,根据实际情况,考虑同时存入字典编码和字典文本,这样可避免部分连接查询。但同时,还是会出现上面提到的问题,一方面是数据冗余,一方面业务表中的字典文本有可能会和字典表中的文本不一致——如果字典信息有更改的话。这里很难找到一种两全其美的办法,既能避免数据冗余,又能让程序在执行读和写动作时都方便高效,如何在各方面之间拿捏均衡是个人经验问题。通常情况下,是在数据的协调性、准确性允许,跨表查询又不容易(从表外键较多)的业务模块,采用在从表中附加额外字段的处理方式;在对数据显示的同步性、准确性有严格要求,跨表查询也相对容易(从表外键较少)的业务模块,采用从表中不设外键以外的附加字段、而使用关联查询的方式获取完整数据信息。在普通的业务系统之外,还有一种情况,可能不得不大量使用函数、子查询、嵌套查询。和可视化部门合作过的一些项目,系统前端引入ECharts,大量的环形图、柱状图、折线图等用于展现数据统计分析结果。有些图形需要的数据很难用简单的SQL一次提取出来,可如果多次提取后再由程序组装处理,又太过麻烦,最后还得考验SQL,此种情况是允许子查询、嵌套查询、多表连接等复杂SQL出现的。过去曾借助外部框架设计出一套异常灵活的架构,封装了查询对象,消除掉了SQL语句,应付通用的业务系统足够,但在做类似这种统计分析功能时却变得各种不自在,到后来还是觉得直接写SQL更方便。此处只能在设计的架构上放开一个口,让开发人员可以自由编写SQL语句提取数据,最终的查询结果统一封装成一个List&Map&String, Object&&,然后交由程序自动序列化成JSON格式(包含多个对象的数组)返回给前端。E.主键外键每张表必须有唯一主键,此主键只用来标识记录唯一,没有其它任何功能,业务表中其它任何的惟一字段均不能做主键,比如用户表中的身份证号、地区表中的编码,虽然也是唯一,但均不可做主键。主键为UUID,统一命名为id,统一为char(32)类型。相较于自增主键类型,使用UUID会导致查询速度稍慢,可用自增主键的话,如果同时支持多数据库就比较麻烦了,比如Oracle实现自增功能必须用序列辅助处理,还有,备份合并不同数据库中相同表数据也会出现冲突,设计分布式架构、横向拆分表也会出现类似问题等等。关于主键,还有一点要强调,原则上讲,多对多关系中间表外的任何其它表不允许出现复合主键。外键,多和主键对应,多是引用另外一个表的主键,那么这个外键及所有表的主键的类型也应该是一样的,都规定成char(32)类型。再就是外键的命名也要统一,这个也可以通过PD由CDM转换成PDM时统一处理,使用“主表名_主键名”的命名方式,比如user_id,如果一个从表中有多个字段同时引用主表的同一个字段,那再用其它标识,比如在会诊单申请表中会诊发起医院(sender_hopital_id)和会诊接收医院(receiver_hospital_id)。主键和外键是数据库设计中非常关键的两个地方,在后面的约束控制和命名规范中还有更详细的介绍。三种数据库关系中,多对多关系是最麻烦的,中间表往往使用复合主键,在程序架构上对这部分业务的处理不太容易,设计程序架构时要特别注意。F.逻辑删除关于针对数据库的删除动作,仔细考虑后还是决定,现阶段暂时仍旧使用物理删除。严格意义上来讲,所有的软件项目都不应该有物理删除动作,目的很明确,就是为了数据的安全性完整性。如果使用逻辑删除,给每张数据库表加上一个is_active字段,数据的安全性完整性虽然可以得到保障,但却跟程序编写带来许多麻烦。比如所有的查询方法都需要额外加上is_active=’0’的判断条件,在涉及多表连接查询时就很不方便。再有,执行假删除动作时的级联处理也会相对麻烦。还有,如果数据表的某个字段要求唯一,并强制约束,比如用户表中的登录用户名字段,设计为逻辑删除的话,一旦有新的同用户名记录就无法插入。但如果不将该字段设置为唯一性约束的,那么在每次插入数据的时候,都需先进行一次查询,看看有无未(逻辑)删除的同名记录存在,低效率是一回事,而且在高并发的系统中,很难保证其正确性。此外,使用逻辑删除,随着项目应用时间的增加,将会有大量无效数据产生,如何处理?如果数据量大到影响查询速度,程序如何做优化?像日志表,很容易就到上百万。如果定期将逻辑删除的数据转移到另外的表中,觉得处理起来也不简单,还可能会有附加问题出现。如果使用脚本定期彻底删除逻辑删除的数据,如何叠加备份这些删除的数据?综合考虑,对于现阶段的项目,逻辑删除所带来的好处有限,但带来的问题却很多。如果平时做好数据备份工作,还是可以预防物理删除隐患的。但心里应该清除,当项目大到一定程度,对数据安全性的要求高到一定程度,使用逻辑删除代替物理删除是必然的,在后面的数据库设计中,可以先小范围的尝试使用逻辑删除,一旦开发模式成熟,就全面使用逻辑删除代替物理删除。G.性能安全对于中小型项目,数据库设计过程中过多的考虑性能问题往往弊大于利,程序部分的设计开发也是如此。不是不考虑,而是不要过多考虑。性能及安全问题太大,这些问题的重要性都是随着项目规模增长的,在中小型项目中过分的考虑只会给开发带来不必要的麻烦。中小型团队,时间人力成本有限,要用在关键环节上,用最短的时间做出成型的项目是最重要的。至于设计开发,尽可能保证好其协调统一灵活稳定性,一旦出现问题或需求调整,可以随时灵活的更改就好。4、字段设置A.字段类型介绍不同的关系型数据库在字段类型的具体化上差异较多,这里无法一一详述,但具体化的字段类型再多,无外乎几种:字符、数字、日期、二进制。下面有三张截图,前两张是一张典型的用户表结构,上面的是PD中的PDM,下面的是导入到MySQL的具体表结构,第三张截图是SQLServer数据库中的一张用户表的结构图:个数据库的某个具体类型,这里无法详述其适用情况,本模块只制定通用的字段设置规范。B.不为空默认值表中应该尽可能避免可为NULL的列,且尽可能显示设置默认值,尤其是被索引的列。在MySQL数据库中,空值是不占用空间的,而NULL其实是占用空间的。再者,MySQL表的列中包含NULL的话,该列就不会包含在索引中,也就是说使用索引是无效的,现在不确定其它数据库是否也是如此。 所以考虑今后可能会使用索引的字段,就要设置字段属性是NOT NULL。比如,如果某个字段后面可能会作为查询关键字使用LIKE的形式进行搜索,就要将该字段定义成索引以提高查询速度,那这个字段属性就是NOT NULL的。除以下数据类型的字段外:timestamp、image、datetime、smalldatetime、uniqueidentifier、 binary、sql_variant、binary 、varbinary,表字段应尽可能显示设置默认值。建议数值型的默认值为数值0,布尔型的默认值为数值1(通常情况下,系统中所有逻辑型中数值0表示为“真”、“正常的”;数值1表示为“假”、“异常的”,这种编码后面还会有介绍),datetime、smalldatetime类型的字段没有默认值,必须为NULL。如果数据库中某个字段有默认值,那么觉得在程序开发过程中,对应实体类的属性应该设置同样的初始化值才合理,记得动软代码生成工具中的框架就是这样设置。之前自己的程序设计中没有注意到这点,自动生成的所有实体类的属性都没有默认值。注意区分NULL和空字符串是不同的,数值型字段中NULL和0更是两码事。如果在数据库设计过程中不允许出现NULL字段还好,但如果有允许NULL而没有设置默认值的字符型字段,程序对记录执行了写空字符串动作和压根未执行写动作是两码事;如果有允许NULL且设置默认值为空字符串的字段,则无法做这种区分。当然,通常情况下,我们认为文本框中空字符串的提交动作等同于未执行写入。有些类似的情况是,在程序开发中,一个空的List对象,或者一个new出来的空对象,和NULL也是不同的,要注意。像订单(会诊单)这种表,取消、退回、安排这些字段的信息都不是必须有的,可以分流到子表中存储,放在一张表中会导致出现很多可为NULL或空值的列。之前并不赞成这种过分分流的方法,因为这会另信息的维护变得麻烦,如再有类似情况,应该根据实际综合判断取舍。也要在设计时尽可能遵守第二、三范式,非主属性完全依赖于码(主键)、消除传递依赖,不要让某张表过分臃肿。C.类型长度设置当字段定义为字符串类型时建议使用varchar而不用nvarchar以节省空间,通常情况下,都要用尽量少的存储空间来存储一个字段的数据,能用int类型的就不用char类型,能用char类型就不用varchar类型,能用varchar(20)的就不用varchar(25) 。char和varchar长度设计需要根据业务实际需要进行长度控制,禁止预留过长空间。比如主键要求用UUID,那就统一为char(32),可以固定的部分就都固定下来。varchar类型虽然根据实际长度进行存储,但内存分配则是根据指定长度,不合理的长度设计会导致内存的不合理占用。varchar是变长存储,字段长度是数据库一种约束,定义合理的长度也可以让人容易理解字段的用途。MySQL中定义的长度如果小于255,字段长度用1个字节表示,如果超过255,字段的长度将固定用2个字节表示。Oracle没有这样的问题。字段定义的长度对索引也有较大影响,MySQL数据库索引存储的长度都是定义的长度,不是实际字符的长度,这是一个非常大的问题,估计主要原因是为了实现简单,所以MySQL在索引上会浪费大量的空间保存字符串。前台、程序以及数据库各部分之间对字段大小的限制务必处理恰当,为了节省存储空间,选取的数据库字段容量在一定范围内应该尽可能小,而为了对程序提供更好的扩展支持,又应该尽可能的设置大些,具体字段类型、字段长度如何设置,根据实际情况取得均衡。而后台程序部分,对数值大小长度应该做好校验处理,确保插入数据库的值大小长度不要超过限制。同时前端也应该给出明确的校验提醒,让用户按提示输入,决不允许不提醒用户而擅自把数据处理后插入数据库中(这种错误真有人犯过)。这样,前端、程序、数据库全方位校验处理,自然可以保证数值的准备性、存取的合理性。除非要保存文章内容, text字段尽量少用,如果要用能拆到冗余表中最好。禁止使用blob类型保存大文本、附件、图片等,对于图片、文档等附件数据库中只保留原始文件名和存储路径。网上也有建议使用其他存储方式的,比如TFS、SFS等,可以参考。禁止使用float、double类型,建议使用decimal替代。decimal(a,b) ,a指定指定小数点左边和右边可以存储的十进制数字的最大个数,最大精度38。 b指定小数点右边可以存储的十进制数字的最大个数。小数位数必须是从 0 到 a之间的值。默认小数位数是 0。比如decimal(5,2)规定了存储的值将不会超过5位数字,并且小数点后面有2位数字。D.Oracle的CLOB在Oracle中,CHAR 为定长字符串,最长2000字节 。VARCHAR2 为变长字符串,最长4000字节。NCHAR和NVARCHAR2分别与CHAR和VARCHAR2相对应,但存储的数据为 NLS字符 。目前VARCHAR是VARCHAR2的同义词。工业标准的VARCHAR类型可以存储空字符串,但是Oracle不这样做,尽管它保留以后这样做的权利。Oracle自己开发了一个数据类型VARCHAR2,这个类型不是一个标准的VARCHAR,它将数据库中VARCHAR类型的列可以存储空字符串的特性改为存储NULL值。如果你想有向后兼容的能力,Oracle建议使用VARCHAR2而不是VARCHAR。在Oracle中没有TEXT类型,但有用于大文本存储的CLOB类型。Clob是指大字符对象,也就是英文Character Large Object的缩写;Blob是指二进制大对象,也就是英文Binary Large Object的缩写;由此可见这两个类型都是用来存储大量数据而设计的。LONG 最大存储2G字符数据,但现在已不推荐使用(改用CLOB);CLOB 在Oracle 9i 及以前,最大可存储4G字符数据 ,在Oracle10g及以后,最大可存储4G*数据库块大小的字符数据;NCLOB 基本同CLOB,就是存储的数据为NLS。在Oracle数据库表中使用CLOB类型字段,最大的问题是备份数据时不好处理。在有些情况下,给政府、企业做项目,只给你Oracle的访问权限,而不给你Oracle所在服务器的操作权限,也就是说自己无法操作Oracle服务端工具。但Oracle的客户端中又没有exp、expdp命令,这样备份导出数据库就不好弄了(此处不提沟通协调甲方处理)。SQL Developer是Oracle的官方工具,用其导出数据库,如果导出的是SQL格式,那CLOB类型字段的数据将直接被忽略——这绝对是无法接受的。官网上有文章说可以将数据库导出为loader或pdf格式,自己尝试导出这两种格式,发现不能导出成单个文件,会导出很多的文件。而且导入时也需要用到额外的工具——Oracle服务端的sqlldr.exe,这样只借助客户端也是不行的。在SQL Developer“工具”菜单下,还有两个选项:“数据库Diff”及“数据库复制”,如果所处网络可同时访问源数据库和目标数据库,可用这种方法互相拷贝数据,但是同样的问题,这种数据库复制方法,仍然是不能处理COLB、BLOB的字段。而且我发现,凡是带有这两种字段的表,在复制时都没有数据,不是相应字段没有数据、是整个表的数据都没有复制,其它没有BLOB、CLOB字段的表,数据拷贝都正常。也曾想使用的PL/SQL Developer工具进行备份,导出了PL/SQL Developer自己的格式(pde)。可是却提示stream read error,到网上一查,原来PL/SQL Developer自己的格式也是不支持COLB 、BLOB类型字段的导出的。之前同事介绍过Navicat for Oralce工具,但其在导出CLOB、BLOB类型的字段时,如果字段中的数据过长,也是无法再正常导入的。这个小工具看似简单轻巧,在执行一些操作时问题却很多,不宜作为一款常用的Oracle管理工具。这样看来,只有expdp命令才能有效导出clob、blob格式的字段了。cd D:\app\bsc\product\12.1.0\dbhome_1\BIN\
exp username/password@tnsname file=C:\Users\Administrator\Desktop\.dmp owner=username
imp username/password @tnsname file=C:\Users\Administrator\Desktop\tnsname.dmp ignore=y full=y statistics=none
不过,如果你虽然没有源数据库服务端的访问权限,却有目标数据库服务端的访问权限,且两个库可在一个网络中访问,也是有办法用EXP命令备份源数据库的。就是让目标数据库服务端的TNS监听源数据库的实例,再利用目标数据库Oracle服务端的exp.exe工具远程导出源数据库,导出导入命令和上面类似:cd D:\app\bsc\product\12.1.0\dbhome_1\BIN\
exp origin_username/origin_password@origin_tnsname file=C:\Users\Administrator\Desktop\.dmp owner=origin_username
imp target_username/target_password@target_tnsname file=C:\Users\Administrator\Desktop\.dmp ignore=y full=y statistics=none
此外,用PL/SQL Developer工具备份数据时,Export User Objects菜单命令导出的是SQL文件,在这里你可以将建表、序列、触发器、存储过程等的SQL语句全部导出成一个文件,但是这里面并不包括数据。要想导出数据,必须用Export Tables……菜单命令,导出DMP文件。当然也可以导出其它格式的文件(SQL、PDE),但建议用DMP格式,因为前面已经说过,如果表中有CLOB类型字段的话,用其它格式的导出方式恐怕有问题。如果一个表不存在,而这个表中没有CLOB、BLOB这种特殊数据类型的字段,用DMP导入数据时PL/SQL会自动建立这个表。但如果一个表不存在,而这个表中又有CLOB、BLOB这种特殊字段,直接导入DMP格式的文件会报错 IMP-00003: 遇到 ORACLE 错误 959。所以在Oracle中导入数据库时应该先执行用Export User Objects导出的SQL文件,这样相关的序列、触发器、表结构都已经建好了,再导入用Export Tables…… 导出的DMP文件,也就是导入其中的数据,就万全了。E.数值类型选择float:浮点型,含字节数为4,32bit,数值范围为-3.4E38~3.4E38(7个有效位)double:双精度实型,含字节数为8,64bit数值范围-1.7E308~1.7E308(15个有效位)decimal:数字型,128bit,不存在精度损失,常用于银行帐目计算。(28个有效位)//结果显示为345.9876,只显示7个有效位,对最后一位数四舍五入。
float f = 345.98756f;
//结果显示为345.,只显示15个有效位,对最后一位四舍五入。
double d=345.442d;
//可以支持28位,对最后一位四舍五入。
decimal dd=345.……
float和double的相乘操作,数字溢出不会报错,会有精度的损失。当对decimal类型进行操作时,数值会因溢出而且报错。Oracle中的数值类型,Oracle只是在语法上支持decimal类型,但是在底层实际上它就是NUMBER类型,支持decimal类型是为了能把数据从Oracle数据库移到其他数据库中(如MySQL、DB2等)。Oracle的NUMBER数据类型的精度:NUMBER(P,S) ,P: 1---38, S:-84---127。S代表的是小数位数,P代表的是总位数(整数位数和小数位数)。所以,平时如果在Oracle中用自增主键,长度设为NUMBER(10)的话,相当于NUMBER(10,0),表示最高可记录到十亿级的数据量。下图是MySQL中的整数型数值类型详述:F.通用字段处理日期时间类型字段,网上有建议,采用int来记录unix_timestamp,自己还是习惯用datetime。不过设计原则是粒度越小越好,所以这里要求日期时间类型的字段,尽可能精确到时分秒,用datetime类型。即便是像生日(birth_date)这种字段,一般只存储到年月日,但在选择字段类型时建议还是用datetime而非date,以防万一。如有部分时间字段着实无须记录到时分秒,则用date类型。严禁使用varchar等字符串类型记录日期时间,更不要把时间猜分,年在单独的字段、月在单独的字段、日又是单独字段,老实讲TM想不明白这种人的设计思路是什么样的。网络IP字段,网上有建议,除特殊情况一律用bigint来记录inet_aton值,但这种存储方式貌似只在MySQL中适用,这里要求还是用varchar存储。关于inet_aton想了解的话可以看下参考文献中的“MySQL的IP处理函数inet_aton()和inet_ntoa() ”。字典编码字段,之前在SQLServer中设计数据库时统一使用char(2)类型,Oracle数据库中统一使用number(2),在MySQL中统一使用tinyint(2)。现在想来最合理的还是设置为tinyint(2),以后数据库字典编码字段统一按此设置。就是Oracle中没有tinyint类型,不知道如果在PD中设置此种类型,导入到Oracle时会自动转换处理还是直接报错。备注字段,尽可能在所有表中都保留这个字段,也是给前端信息录入预留一个可扩展部分。统一命名为remark,字段类型为varchar(200),最多100个中文字符。再多的话说明有额外信息,就不适合放在备注字段中了,要再加新字段存储。排序字段,不是每个表中都需要额外的排序字段,但有些表这必须有,比如记录菜单信息的表、门户网站中存放文章内容的表等。这里推荐统一使用int(10)做为所有表中的排序字段类型。字段设置部分撰述内容较多,相对详细,这是比较重要的一部分。以后的数据库设计,字段类型选择、字段长度设置部分都要以此为依据。5、相关注释数据库是整个项目的地基,后面程序架构设计及具体开发工作都要在此基础上进行,如果没有注释或者注释混乱,会给开发者带来很多困扰,无形中影响项目进度。在相对成熟的技术团队中,所用开发模式、架构、框架也都已经成型,如果接手的项目类型不超出平时常规的范畴,以往的开发模式、架构及所用框架等都是无须做大的变动即可拿来复用的。这样,在数据库设计过程中或完成之后,程序的具体设计开始,再到进入正式开发过程中,需要频繁组织开发人员参与的会议。会议讨论的都是具体的开发工作,数据库文档是参考依据、必须的会议资料。数据库文档一般根据PD中的数据库文档模板生成,PD自带的数据库文档模板太杂乱,所以最好单独设计一套适合自己团队使用的模板。比如平时在数据库设计过程中不用存触过程、触发器、序列、函数等高级功能,那我设计的模板自然不包括展示这些信息,只显示表结构、约束、表注释、字段注释等信息,生成的文档也会简单明了。如果不想单独设计,网上也有一些他人整理的模板,或可根据实际情况拿来使用。 团队内部使用的数据库文档一般是HTML格式,查看比较方便,而对外提供的,向PMO或客户提交留存的,一般是RTF或DOC格式的。用PD完成设计之后,将PDM导入到数据库,同时生成数据库文档,后期所有针对数据库的讨论都会以这份数据库文档和PDM图为依据。后面数据库表结构如有变化,文档会同步更新。而这份文档中的文字说明内容,就来自于数据库设计过程中的相关注释。再有,现在的程序设计好之后,具体代码大都是由工具生成,程序中的实体类、方法说明等等最终也都是由数据库中的相关注释演化而成。所以注释说明的语气,甚至标点符号都要注意,只有数据库注释规范了,数据库文档、程序注释、程序文档、对外接口文档才能规范,因为这些的起始点都是在数据库中的注释上面。数据库中的关键注释其实就两部分,一部分是表注释,一部分是表字段注释。表注释对应程序中实体类的注释,字段对应程序中实体类属性的注释。A.表注释对于表的注释,要求简单明了,先说明表中文名称,句号分隔,然后跟功能说明,无需特别说明的,则只说明中文名称即可。同时,为了最终生成代码注释的可读性,不允许在说明中出现“表”字眼。比如订单表,直接注释“订单”即可,如核心业务表需要其它特殊详细的功能说明,要考虑到最终生成程序实体类注释的可读性。再有,如果数据库由多人协作设计,那表注释中必须标明创建者和创建时间信息,示例如下:创建者:孟宪志。创建时间: 13:30。说明:系统日志。用于记录用户对系统的所有操作。
数据库设计完成进入开发阶段,后续扩展新增的表也都要按如上格式注释,同时说明是后续新增表,及新增原因等。B.主键字段主键字段,无须特别注释,注释就两个字:主键。C.外键字段外键字段,注释先说明字段中文名称,句号分隔,后面要特别说明是外键,然后说明引用哪个表的哪个字段,再句号分隔,如还有其它说明,则继续跟后面。比如:` applicant_doctor_id` char(32) DEFAULT NULL COMMENT '申请医生。外键,引用医生表(doctor)的主键(id)。理论上可填多个,以“|”分隔'。
前面说过为了避免多表连接查询,有关联关系的地方,一般从表中除了有引用主表主键的外键字段外,还要有一个或多个扩展字段存放主表中的关键信息,这个扩展字段通常都是和对应外键字段并列存放,注释时先说明字段中文名称,句号分隔,后面要特别说明是名称(或其它),然后说明和哪个表的哪个字段对应,再句号分隔,如还有其它说明,则继续跟后面。格式如下:` applicant_doctor_name` char(32) DEFAULT NULL COMMENT '申请医生。名称,和医生表(doctor)的医生名称字段(name)对应。理论上可填多个,以“|”分隔'。
D.字典字段字典字段在数据库表中出现非常频繁,要求所有表中的字典字段注释也要统一格式。注释先说明字段中文名称,句号分隔,后面要特别说明是编码,对应哪个字典表的哪个字段,再句号分隔,后面跟详细说明,如果字典项不多的话,要求先枚举说明每种字典编码代表的不同意义,句号分隔,如还有其它说明,则继续跟后面。比如:`status_code` varchar(5) DEFAULT NULL COMMENT '转诊单状态。编码,对应数据字典表(dictionary)中的编码字段(code)。目前先定义6个状态:01 已提交,02 已取消,03 已审请,04已安排,05 已拒绝,06 已结束。03是向HIS系统执行审请,04是HIS系统已安排入院日期,下转诊时这两个字段没有区别。'
如果有字典文本扩展字段(类似于外键的扩展信息字段),格式与上类似:`status_text` varchar(50) DEFAULT NULL COMMENT '转诊单状态。文本,对应数据字典表(dictionary)中的字典项名称字段(name)。目前先定义6个状态:01 已提交,02 已取消,03 已审请,04已安排,05 已拒绝,06 已结束。03是向HIS系统执行审请,04是HIS系统已安排入院日期,下转诊时这两个字段没有区别。'
字典表细分的话也有好多种类型,后面特别说明中还会细讲。除了数据库中的通用字典表,还有一些常见表,比如地区表、ICD字典等,也是一种字典表,其共性是:表结构设计完成后、程序开发前即完成数据填充,且后期很少改动;主键外至少要有编码和文本两个非空字段,如果字典表中有细分子项的话,还会有字典项所属类型字段。E.普通字段除以上三种常见类型的字段外,其它字段,都可用统一的方式注释。先说明字段中文名称,句号分隔,后面跟详细说明。比如:`bed_id` varchar(50) DEFAULT NULL COMMENT '入院床位号。HIS系统安排并反馈的入院床位号,如果是下转诊,此部分由医生手动填写'。
还要特别说明的是,如果项目进入开发阶段后需要对现有表新增某些字段,或对现有表的某些字段进行修改,和新增数据库表一样,也必须特别说明。创建者:孟宪志。创建时间: 15:38 。说明:会员职务。交易平台新增字段,个人用户此字段为空。
相关注释部分,先说明了数据库中注释对项目开发的重要性,然后分五个子模块:表注释、主键字段、外键字段、字典字段、普通字段,详细介绍。如今后所有的数据库设计都能严格按此规范要求、按给出的格式添加注释,则相关数据库文档、程序文档、接口文档都可随之走向正规。6、约束控制建立约束的目的是为了防止数据库中出现不符合语义规定、不符合业务逻辑的数据,为了确保数据的完整性、合法性。如果数据具有完整性,则表示数据有效——正确并且准确、数据库的关系结构是完整的。完整性约束可以加强数据库的关系结构,这些规则使数据在各个表之间保持一致。总的来说有五种约束类型:唯一性和主键约束、外键约束、检查约束、空值约束、默认值约束,对应五大关键词,UNIQUE和Primary Key, Foreign Key, CHECK, NOT NULL, DEFAULT。这五种约束类型,除检查约束外,其余的在前面的章节中都有过介绍,比如主键、外键字段类型的选择,字段长度的设计,注释的规范等等,在后面的命名规范中也还会提到。检查约束(CHECK),用于检查列的类型和范围,语法:CONSTRAINT [constraint_name] CHECK (condition); 比如:check(Age &2)。过去没有在数据库中添加检查约束的习惯,在本规范中,也暂不做此要求,这会增加数据库设计过程中顾虑点,还是交由程序和前端来控制这种细节上的数据合法性。本规范中要求,除检查约束外,其余四种都要在数据库中加强约束,同时,程序也会根据数据库中约束的设置做相应处理。主键不用说,一般情况下都会加约束的。要注意的是唯一字段,比如用户表中的电话、邮箱、登录账号等等明显唯一的信息,都要加强约束,还有多对多关系中间表里的复合主键,也要加强约束。再就是,前面也提到过,本规范中所有主键字段统一使用UUID,char(32)类型,具体命名方式后面也会讲。外键部分,类型自然要和主键一样统一为char(32),除了外键字段,为了保存主表其它信息的扩展字段类型也要和主表中的相应字段类型统一。过去参与的项目中有的在数据库中加了外键的强约束,有的则没有,有的是在用PD设计时加上了主从引用关系,但在导入到库中时去掉了外键的强约束,而只保留表结构。表面看,数据库中加上外键、非空、唯一等强约束会给程序编写带来麻烦,实则不然。约束是为了保证数据的合理性,如果数据库设计的约束本身没问题,那程序编写中因约束而照成的不便就多是程序本身的不合理造成的。万千世界,所有约束规范都是为了确保被约束规范的对象将所参与的事情做的更好,这种最终的好不是只针对某个对象的,而是针对所有参与其中的。假如某种规范不是这样,那它本身就是不合理的;假如它是这样的,而被约束规范的对象觉得在这种约束下做事情不便,那就是他自己做事方法的问题了,要由他自己根据规范修正。所以强约束带来的不便只幻象,这种不便不但不是坏事,还会倒逼程序开发更加趋于合理,修正开发中的错误。而不加强约束,程序可以肆无忌惮的对数据库进行任何操作时,如果架构设计师及开发人员的经验、技能较强还好,否则的话,程序很可能会因有意无意读写错误信息,造成针对数据库的无效或错误操作,破坏掉数据的完整性、合理性。有些情况下,加不加强约束设计者是决定不了的,比如公司有通用的权限管理系统对所有子项目统一管理,那在设计子项目的数据库时就不能添加和用户相关的外键约束了。还有其它类似的情况:两个项目之间有逻辑交差,但数据库相互隔离,只能通过互相调用接口处理业务。这种情况下,如果想保证好数据的完整性准确性,只能由程序在业务逻辑层控制,必须设计开发足够精密才能做好。空值约束和默认值约束不再多说,在前面字段设置中的NOT NULL子模块讲的很详细了,只要记得设置字段为NOT NULL、并给字段设置默认值可以提高查询速度、节省表空间就可以了。7、索引添加索引是一个单独的、物理的数据库结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。数据库中索引的概念与书索引的概念非常类似,不同之处在于数据库索引用来在表中查找特定的行。在各种类型的数据库中,索引又可细分为好多类型,比如之前系统整理过Oracle中的索引分类:非唯一索引(最常用)、唯一索引、位图索引、局部有前缀分区索引、局部无前缀分区索引、全局有前缀分区索引、 散列分区索引、基于函数的索引。Oracle存储索引的数据结构是B*树,位图索引也是如此,只不过是叶子节点不同B*数索引。并未做过严格对比,不清楚添加索引后对查询速度的提升到底有多少,对插入删除修改的速度影响又有多少。就过去的经验,对于Oracle来讲,百万级数据量一般不会出现明显性能问题的,无需做特别的优化;MySQL的话,超过五十万条数据就有点卡了,超过一百万就得做优化了。对于诸多中小型的企业内部应用系统,如果数据量未达到这个级别而出现查询性能问题的,多是因为程序,开发模式、架构、框架、编码细节或SQL语句中肯定有特别不合理的地方。所以对于当前阶段的项目,在出现查询性能问题之前,不建议在数据库设计过程中手动添加索引,而且大多数数据库是会自动给主键和有唯一约束的字段添加索引的。当数据量达到一定程度,仅通过程序优化对性能提升有限时,可以考虑同时对数据库进行调校,这时会优先考虑建立索引。在前面的字段设置中的NOT NULL子模块提到过NULL值对索引的影响,下面再列出一些索引使用注意事项,大都是从网络上整理出、自己认为比较合理的,如果要建立索引,尽可能遵循这些规范(第一条没大看明白):a. 逻辑主键使用唯一的成组索引,对系统键(作为存储过程)采用唯一的非成组索引,对任何外键列采用非成组索引。考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写。b. 大多数数据库都索引自动创建的主键字段,但是可别忘了索引外键,它们也是经常使用的键,比如运行查询显示主表和所有关联表的某条记录就用得上。在经常进行连接,但是没有指定为外键的列上也要建立索引,而不经常连接的字段则由优化器自动生成索引。c. 在频繁进行排序或分组(即进行 GROUP BY 或 ORDER BY 操作)的列上建立索引。d. 不要索引blob/text 等字段,不要索引大型字段(有很多字符),这样作会让索引占用太多的存储空间。e. 不要索引常用的小型表,不要为小型数据表设置任何键,假如它们经常有插入和删除操作就更别这样做了,因为对这些插入和删除操作的索引维护可能比扫描表空间消耗更多的时间。f. 在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要建立索引。比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就无必要建立索引,因为建立索引不但不会提高查询效率,反而会严重降低更新速度。g. 如果待排序的列有多个,可以在这些列上建立复合索引(Compound Index)。h. 索引不是越多越好,添加或删除表记录时,必须花费额外的时间来更新该行的索引。读的方便,写的就会有麻烦,反之,亦然。8、特别说明A.数据字典表通用字典表的表结构如下:/*==============================================================*/
/* Table: Dictionary */
/*==============================================================*/
CREATE TABLE [dbo].[Dictionary](
[dictId] [varchar](50) NOT NULL,
[dictTypeId] [varchar](50) NOT NULL,
[code] [varchar](50) NULL,
[name] [varchar](200) NULL,
[remark] [varchar](1024) NULL
/*==============================================================*/
/* Table: DictionaryType */
/*==============================================================*/
CREATE TABLE [dbo].[DictionaryType](
[dictTypeId] [varchar](50) NOT NULL,
[name] [varchar](50) NULL,
[remark] [varchar](1024) NULL
过去接手项目的字典表大都是这样设计,在找到更优设计之前,字典部分延续使用此结构。不建议在通用字典表中分等级,如果有要分级的字典数据,建议额外建表处理,比如地区字典,或者是左侧菜单(严格来讲,左侧菜单已经算不上字典)。网上有建议将字典项放到XML文件中维护,如果是某些特定的字典项,比如刚提到的菜单项,数据量较少还可以,超过一定量就不现实了,对于大多数业务系统,通用字典表是必须有的。自己对于字典数据的定义是,可枚举,系统运行前即被录入、运行后除非有特别权限出现特别情况不可随意更改添加删除。除了通用字典表外,全国省市县地区信息表、医疗系统中存放ICD数据的表等,原则上来讲也是一种字典表。关于布尔型字段,比如男女、是否、对错等,过去的设计中没有使用数据库特定布尔类型定义的习惯,都是放在字典表中统一定义,后面的设计中也要求如此。对于编码,习惯用0和1,编码规则通常是:0是多数的、常见的、正确的、主要的、正常的,1是少数的、少见的、不正确的、次要的、不正常的。比如是否中0代表是、1代表否,对错中0代表对、1代表错,男女中0代表男、1代表女,建议布尔型字段的字典编码延续此编码方式。虽然在业务表中的相关字典字段存编码已经成为自己的一种习惯,但和同事协作时发现还有人直接存文本,有必要申明这一点,字典字段绝不能只存文本,这关系到整个项目的统一性协调性完整性。在前面的“设计规范”——“基本原则”——“连接查询”部分专门提到过字典字段,有时候,在较为核心的业务表中可能出现五个甚至更多的字典字段,比如订单表,如果只存字典编码,如何一次查询出核心业务表中字典字段对应的文本信息?全部都使用对字典表连接查询的话效率太低了,这种情况下,通常将字典编码和对应文本一并存入,至今未找到既可以只存字典编码又可高效查询的方法。在程序开发过程中,具体到某一常用字典类型、字典项的编码和文本信息需要即时获取,以往的习惯在程序中建立一个常量类,所有用到的字典数据在里面标明。前端部分也会有一个常量JavaScript文件,和后台程序中的常量类功能一样,记录常用字典类型、字典项编码信息。比如:public static final Integer DICTORY_ITEM_ID_USERTYPE_PERSONAL = 1;
public static final Integer DICTORY_ITEM_ID_USERTYPE_ENTERPRISE = 2;
public static final String DICTORY_ITEM_TEXT_USERTYPE_PERSONAL = "个人用户";
public static final String DICTORY_ITEM_TEXT_USERTYPE_ENTERPRISE = "企业用户";
JavaScript文件:var DICTORY_ITEM_ID_USERTYPE_PERSONAL = 1;
var DICTORY_ITEM_ID_USERTYPE_ENTERPRISE = 2;
var DICTORY_ITEM_TEXT_USERTYPE_PERSONAL = "个人用户";
var DICTORY_ITEM_TEXT_USERTYPE_ENTERPRISE = "企业用户";
这里单独强调一点,目前使用的region地区字典表,存放全国省市县的信息,里面有必要加入一个是否可见字段(is_display )和一个备注(remark )字段。另外,通用地区字典表应该考虑到世界各国家、镇、乡、县级市、市下面区、市下面县的问题,中国一级行政区使用国家统计局定义的编码,世界国家使用ISO-3166-1标准中的Alpha3编码。当前的设计在存储、处理世界上国家的编码、中英文名称等信息时已经不适,而要新增对镇、乡、县级市、市下面区、市下面县的存储,编码规则也要重新整理才可以满足,届时可以参考网络中的标准数据,不要随意编制。相信以上关于字典的处理还有更好的方法,在后续的开发中会探索留意总结。B.系统日志表以往设计的项目中日志分三部分:一部分是系统登录日志,一部分是用户操作日志,一部分是运行异常日志。如果系统上线前测试没问题,运行时异常出现的概率较小,一旦出现多是外部因素所致,比如网络中断数据库失联等等,这部分通常记录在本地日志文件中的。系统登录和用户操作则要记录在数据库中,要有相应表存储,下面给出之前设计的表结构:/*==============================================================*/
/* Table: LoginLog */
/*==============================================================*/
CREATE TABLE [dbo].[LoginLog](
[loginLogId] [varchar](50) NOT NULL,
[userId] [varchar](50) NULL,
[loginTime] [datetime] NULL,
[logoutTime] [datetime] NULL,
[durationTime] [bigint] NULL,
[ip] [varchar](50) NULL,
[status] [varchar](5) NULL,
[browser] [varchar](50) NULL,
[resolution] [varchar](50) NULL,
[ipAddress] [varchar](50) NULL,
[operatingSystem] [varchar](50) NULL,
[userName] [varchar](50) NULL,
[userPassword] [varchar](50) NULL
/*==============================================================*/
/* Table: OperationLog
/*==============================================================*/
CREATE TABLE [dbo].[OperationLog](
[operationLogId] [varchar](50) NOT NULL,
[loginLogId] [varchar](50) NULL,
[userId] [varchar](50) NULL,
[operationTypeCode] [varchar](2) NULL,
[operationTable] [varchar](50) NULL,
[operationContent] [varchar](500) NULL,
[isSuccessId] [varchar](2) NULL,
[resultCode] [int] NULL,
[objectRecordId] [varchar](50) NULL,
[resultMessage] [varchar](1000) NULL,
[totalCount] [int] NULL,
[addTime] [datetime] NULL
过去的设计中,几乎所有表中都设有create_time、create_user、update_time、update_user四个字段,如果操作日志表设计的合理、又有相应程序配合足够严密的话,除核心业务表外这四个字段完全可以拿掉, 所有针对数据库的增删改查动作都会在日志表中有迹可查。但现在的系统登录日志及操作日志部分仍有很多问题未处理好。第一个是登录日志中对于登录时长的记录,因为目前写的程序无法确定用户离线时间,所以这个字段的数据无法计算。第二个是操作日志中对非登录用户操作的记录。接触的大都是Web业务系统,非登录用户是不能对系统进行操作的,但如果项目中有对外部分(Public)呢,比如网站,那这些查询动作要不要记录呢?非登录用户的查询动作记录的意义不大,除非是搜索动作——如果有这个功能的话,有注于分析用户习惯。但如果业务系统较大,搜索部分比较重要,应该有单独的搜索日志记录功能才好。第三个是操作日志中对于增删改查动作的细分。查询操作较为频繁,无论用户是否登录,其在系统中的每个动作都有可能触发对数据库的查询,对这部分的记录处理的不是很好。不是不好记录,而是不好对查询记录进行分类。通常情况下,增删改这类写操作都要记录日志的,不过有些查询操作却没有记录日志,比如当用户在登录系统时,也是调用的查询方法,但有登录日志功能专门对这个操作进行记录,那这个查询操作实际并无必要记录在操作日志中。再比如,用户在新增卡片信息时,系统可能要先判断一下这个卡号是否已经存在于数据库中,并给出相应的提示,那这个系统业务自身执行的操作还要不要记录在操作日志中呢?过去没有对这些查询进行记录,但是不是可以完整记录,然后对操作记录进行分类,哪些是用户直接解触发的、哪些是间接触发的由系统业务执行?可不可以把操作来自于哪一个页面哪一个控件、执行的哪一个动作都进行分类记录,以方便后期查阅呢?过去接手的项目,未登录用户多是没有写权限的。现在的程序架构,日志记录功能放在了Service层,如果对查询动作细分其来源的话,则当前架构需要调整。如果仅仅区分是否为登录用户的操作还好,如果要记录哪些是用户直接操作、哪些是由系统业务执行、甚至细分动作来源就不容易了,这些都是要做参数由Controller传入Service的,或者将日志记录由Service中去除,分散到Controller中,真这样做内聚性就差了。目前的架构,可做的就是,对于未登录用户的操作及用户间接触发的动作不做记录,只记录登录用户直接触发的动作。第四个是操作日志中对于增删改查详细内容的记录。比如增加的话增加了什么、查询的话查到了什么、删除的话删除了什么,修改的话修改了哪些属性、修改前后属性值各是什么。把这些操作结果序列化成某种格式存储在日志表中到也不难,问题是都存入数据量太大了,想不到可以精确存入少量数据的方法。第五个是操作日志记录的备份。当前阶段的数据库中,操作日志表是数据量增长最块的,过去并无有效方法处理,只能用脚本定期删除历史数据。网上有建议,日志类数据不要直接存储在MySQL上,优先考虑Hbase或OB,如需要存储请找DBA评估使用压缩表存储。也有建议,采用活动库与历史库分开设计,提高系统访问即时数据的效率。认为合理又相对简单的办法还是后者,定期迁移过期日志数据到备份库中。此过程应该也可以用脚本处理,或者尝试寻找用工具自动处理的方法。对于日志记录存取相关的问题,都未能找到特别好的方法处理,以上解决方案只是建议,也会在后续的开发中继续探索留意总结。C.用户权限表对于权限的控制,由高到底大致分这几个级别:系统级、模块级、菜单级、页面级、控件级、数据级。菜单、页面、控件的落脚点都在请求链接地址上,数据级的权限最难控制,不同的角色对不同的数据有不同的操作权限,要对数据进行分类,自己过去负责的、接触的项目中很少有对数据级权限做到灵活控制的。系统级的权限表示可以控制不同项目,平时的单一项目无须考虑。就是说在现阶段只要控制好中间几项就可以了,相关设计都是可复用的。如果对用户、角色、权限相关的内容详述的话,再写这样一份文档也讲不完,这里只简单一提,具体设计不讲。业务系统的权限控制功能必不可少,但真正设计好的却不多,这部分的根本解决方案还是要开发通用的权限管理系统,对所有项目统一管理。对于软件研发公司、团队,这是一劳永逸的工作,但必须要有足够经验能力的人牵头做。D.并发编辑处理在设计程序架构时应该考虑这样的问题,比如当一条会诊记录的状态是刚提交时,那么会诊申请医院和会诊接收医院都可以对这条记录执行操作,会诊申请医院可以取消修改会诊信息、会诊接收医院可以拒绝或安排专家。如果两个用户在同一时间段操作的话,很可能出现冲突。比如会诊申请医院有可能正在取消页面中填写取消会诊的原因,而会诊接收医院恰好也进入了会诊处理页面正给同一会诊申请记录安排专家。类似的情况还很多,比如当系统用户位于修改页面中正在编辑某条数据时,恰巧有另外的用户对此条数据执行了删除动作,这时修改完后的提交动作就会出现异常,如何避免这一类的问题?有个想法是,可以给数据库表加个布尔型的锁字段,当有用户可能对此表中的某一记录执行写动作时,比如进入修改页面,标识锁字段(加锁),任何用户在想对此条记录执行其它的修改动作前,要先查看锁字段是否处于加锁定状态。可问题也有,BS的系统中程序如何判断用户已经停止可能的更改动作,而恢复此标志为解锁状态呢?比如用户可能进入修改页面后,并未执行修改动作,而是直接在浏览器中关闭了此页面,但此时记录却还处于被锁状态。此种类似悲观锁的处理方式之所以不可行,因为以上设计思路中妄想用数据库中的表字段标识用户进出页面的动作,可在BS的系统中,程序是无法监听到客户端页面释放的。再有,此设计中锁的资源其实质是数据库中的表记录而非页面,而在实现时却想用其去锁页面,也不甚合理。由此,对于锁,首先应该明确锁的内容,其次应该明确添加、释放动作是否可被捕获。那换种思路,不修改数据库表设计,不加额外的锁字段。后台程序在执行修改动作时先做判断,注意此处说的是后台程序而不是用户,是在后台程序执行针对数据库的写操作时而非用户进入修改页面时。先根据主键对相应记录执行一次查询,如果有早前的操作导致本次操作无效,则给出提示,比如该记录已被删除、该会诊申请已被取消不能安排专家等等。但此种解决方案只能解决记录被删除、会诊单状态被修改这种特定性的情况,无法处理该记录和提交修改前的初始记录不同的广泛型问题,因为程序不好在执行写操作前,逐个判断整条记录的每个具体字段。有可能此条记录已被删除、有可能是会诊单状态有更改、也有可能是病情描述有修改。如果申请医院修改的是病情描述,那接受会诊医院再做写操作提交,就会把之前的病情描述覆盖掉。所以对于并发编辑的问题,目前唯一可行的方法,还是在数据库中加入一个标识字段。不过此字段不能是布尔型,而是数值型或日期时间型。程序在执行修改前先执行一次查询,检查此字段当前的值(时间)和本修改提交前获取的原始值(时间)是否一致。如果一致,则此字段的数值发生变化,同时正式执行针对记录的修改动作;如果不一致,说明此条记录在当前的修改期间被其他人修改过,此修改动作作废,给出前端错误提示。但这样的不好之处是,用户有可能在操作完之后才发现,自己的之前的操作是无效的。比如在修改页面都已经填写完要修改的信息了,点击提交才给提示此条记录已被删除。理想的悲观锁解决方案应该是:既然有人正在编辑此条记录,那在这段时间,其他人则不能进入针对这条记录写动作的页面、不能执行针对这条记录的写动作。但前面也说过了,在BS的程序中,前端页面的释放动作无法捕获,注定此方案不好实现。严格来讲,所有数据可修改的表中都应该有这样的锁字段来处理并发,可以在程序的业务逻辑层对修改方法进行统一控制,校对锁字段。以往的数据库设计、程序设计中,对并发编辑的处理考虑欠缺,很多处理也不甚得当,要引起注意。E.历史版本设计在数据库设计过程中,经常会遇到一个需求,就是希望把操作之前的数据保留下来,能够看到操作之前是什么数据,操作之后是什么数据。对于这种需求,我们可以使用保留历史数据或者使用版本来实现。版本号是一种常见的版本设计方案,就是在要进行历史数据保留的表上面增加一个版本号字段,该字段可以是datetime类型,也可以是int类型,每进行数据操作时,都是创建一个新的版本,版本是只增不减的,所以只需要拿到最大一个版本号,就能得到最新的业务数据。版本号和上面针对并发编辑加锁的解决方案类似,两者表现在在数据库中的设计完全一样,都是加一个标识字段,可以是数值类型或时间类型。不过程序的处理不一样:版本号的设计中程序会在同一张表中存下记录修改的历史;标识锁的设计,只是为了给某一记录加锁,处理并发编辑问题。个人不建议将修改的历史记录和业务数据混淆在一起存放于业务表中,因为程序读取数据时要先对版本号字段进行判断、程序的修改动作在程序中实质也变成了插入动作,多了很多逻辑处理,况且一起存放容易使业务数据表的数据量因历史版本记录而膨胀。历史版本记录可以单独建历史表存放,其实就是建立相同Schema的表(当然也可以添加更多的字段用于记录额外的历史版本信息),该表只保留历史版本的数据。这有点像一个归档逻辑,所有历史版本我们认为都应该是不经常访问的,可以扔到单独的表,对于现有生效的版本,仍然保留在原表中,如果需要查询历史版本,那么就从历史表中查询。使用历史表记录历史版本,就是在程序对数据进行增删改操作时,先在历史表中留痕。对于会诊单这种核心的业务表,保存历史修改记录是很有必要的,但并非所有的表都一定要保存历史记录,对于其它一些非核心表,可根据实际情况斟酌是否建立对应历史表。不过合理的设计应该是一套完整的体系,没有重要不重要之分,只要存在的都是重要的,都要用严格统一的设计方案。为此或可以创建额外的历史版数据库,里面单独保存所有的历史表。这里有必要再次提下前面系统日志表设计部分的介绍,里面说可以把每次的写操作序列化成某种格式存储在操作日志表中,如果操作日志的设计可以记录的足够详细灵活——增加的话增加了什么、删除的话删除了什么、修改的话修改了哪些属性、修改前后属性值各是什么,具体到某张表的历史记录或可不用再单独处理。以往的数据库设计中,多没有考虑详细的历史记录功能,后面应该注意,再仔细考虑下操作日志(OperationLog)表的设计和存储(优先考虑Hbase或OB),看看可否将其设计的足够详细灵活。F.大数据可视化在“设计规范”——“基本原则”——“连接查询”部分提到存有大量可视化图形展现的系统,对于这种系统如何提取通用部分,以便高效、严密、灵活而又统一的控制,尚未有好的解决方案。业务、约束在这样的系统中不是核心;前台只有读而没有写,对读的要求很高,对写却不在意;只要统计分析的结果,而不要源数据。按理没有源数据,自然没有统计分析,但有时这是个大数据平台,这些源数据根本拿不到,它来自于整个市场、整个互联网。但是统计分析的结果可以从网上搜到相关,跨过源数据而直接显示。对市场和行业进行大数据分析是非常困难的,不是说分析困难,而是拿到数据困难,单凭爬虫团队从网上爬取的那点乱七八糟的数据,用来分析根本不现实。互联网之外,行业内部的数据又都掌握在政府或企业手里,除非有非常亲密的合作关系,这些数据也是拿不到的。而且手里有大数据的机构或企业,往往自己就有能力进行数据分析,有大数据却没能力分析又找到我们做,是最理想而少见的情况,这就无需担心数据源,项目也就是纯粹的技术问题了。做大数据分析平台,当然首先得有大数据,否则出来的系统就是无源之水、无本之木。问题是现在没有,还想做数据分析可视化展现,该当如何?首先是需求提出者那边要立足于实际,不要凭空的去想要一个东西。没有数据也不知道数据具体从何而来,却妄想做大数据分析,这是一切的症结所在,所接触项目的痛点根源就在这里。但另一方面我们可控制的又很少,有人愿意付钱,无论痛不痛到你这里都要做的,没得选择。其次是产品经理那边,在接到客户的模糊需求后开始设计产品,先考虑的问题是实现,要设计这个功能数据源从哪里来,可否实现?这些客户那边不考虑没办法,产品这边如果也不考虑而天马行空的设计,最后到开发那边就全懵逼了。如果没有源数据,那要展示的统计分析结果,互联网上可否获取明确的数据?这里说考虑实现不是泛泛的,而是对于设计的系统中的每一处,所需的数据都要有明确的数据来源方可。按常理,产品经理在设计前应该先过项目经理这边,详细沟通之后再着手设计,而且设计过程要和项目经理实时沟通。但当前所在公司的情况就是产品经理在拿到需求后直接设计,很容易脱离于业务,且其没有能力考虑到后期具体的实现问题。如果是纯粹的后台业务系统,交给产品经理设计问题会更多。等到完成设计再交付到项目经理这边组织人员开发,有不合理的地方项目经理很难再强力左右,总不能让他再重新去设计,只能默许当前的设计、提些细微处的修改意见后着手开发。再说,工作流程有问题,前期及设计过程中不和项目经理实时碰面,返回重新设计多少次还是会有问题。这样设计和实现就脱节了,一个烂的系统在前期就已经注定。最后到开发这边,应该先确定系统涉及哪些业务、自己可以拿到哪些真实的源数据、哪些真实的数据处理析结果,对于有源数据的部分可以先理清其中的关系,对其进行关系化存储,而对于没有源数据只有数据处理分析结果的部分则要另当处理。自己以往做的这种项目,都是先理清业务关系,然后结构化设计数据库,如果最终只有数据处理分析结果而没有源数据,则制造模拟源数据,以这些模拟的源数据计算出准确的分析结果为最终目标。在制造模拟源数据时非常不便,因为结构化的存储、业务关系,表与表间互相干涉,影响着SQL查询出的最终分析结果。也就是在这时开始想,对于这种前台界面中只展示数据处理分析结果的项目,结构化的数据、关系型数据库可能不是最好的选择,用非关系型数据库会不会更灵活一点?只有分析结果或只有源数据都还好说,问题是大部分项目都介入两者间,有部分有源数据,有部分只有分析结果没有源数据,这些有的源数据和有的分析结果间可能还有些业务上的联系。比如酒企信息这些源数据本可以获取一部分的,但各省份的所有酒企的具体信息却是拿不到的,但同时各省份拥有的酒企数量排名这个统计分析结果却是从网上可以搜到的。这TM就尴尬了~~~本来在关系型数据库中有酒企和地区表,多对一,但为了得到这个分析结果,我要在酒企表中制造大量模拟数据,来平衡得到下面的分析结果。如果不这样做,除非针对这种只有分析结果没有源数据的部分单独设计表存储,但这样关系型数据库就全乱了,也发挥不了他应有的作用。现在想到的一个办法是针对这种只有分析结果没有源数据的部分单独存储成XML数据,或者就是用非关系数据库存储,对那些有源数据而又涉及业务的部分还是用关系型数据库存储,在程序中对这两种数据分别处理。以往没有试过这种方法,后面可以尝试下,是否会让后期的开发及数据维护更简单些?自己后期这种纠结的根源,还是在前面的需求提出和产品设计中,如果这两个步骤自己可以强力左右,定然不会让后期开发出现这种进退不得的情况。过去一些项目,项目经理、产品经理、技术经理的角色都是一人独揽,反而是效率最高、对项目最为有益的。个人是敏捷开发的极力倡导者,在项目调研、设计、开发、实施的整套流程中主张独裁,极其厌恶带庞大臃肿的团队、极其厌恶使用低效的传统开发模式。G.其它注意事项在建表时的字段排列顺序也要注意,虽然在使用相应的数据库管理工具时,一般可以按名称对表字段进行排序显示,但建表时默认排序最好和字段的重要程度有一定关联,这样开发人员在查看表结构时会一目了然。而且表一旦建完,在一些数据库中想要再修改其字段默认顺序就不容易了。一般是基本的、核心的字段在前,次要的、扩展的字段在后。这个默认的顺序,约是你在建本张表时,脑海中先后浮现出的字段的顺序。在数据库表设计过程中,不建议提前加扩展字段,当前想到有几个字段则就有几个。加扩展字段主要是为了方便后面开发过程中需要新增字段的情况,但是,最后需要增加的字段可能和你设定的字段的类型不一样,这样扩展字段还是没用的,需要手动更改,再说字段名称也都要改,那还不如不加扩展,有需要时再添加呢。设计完成后可以用工具添加些测试数据,不过工具添加的数据多不规则,这个根据情况而定吧。9、梳理总结“设计规范”几乎把数据库设计过程中的各个注意点都提到了,且详细讲述了各注意点涉及的知识面,并将自己的设计理念灌入其中。现把此部分的要点梳理如下:a. 数据库设计过程中使用PD工具。b. 百张表内的数据库由一人来设计。c. DBA应该是在被需要时出现,而不应该被强制需要。d. 开发过程中的规范和约定采用大一统的方式,严格限制脱离中央管控的脚本或代码出现。e. 设计原则是尽可能让粒度小、容忍度高。f. 负责数据库设计工作的人应该是最懂项目、最懂业务需求、最有设计经验的人g. 把项目相应部分的决定权交到相应最懂的人手中,其他人不要干涉。h. 这里建议将MySQL数据库编码设置为utf8, SQLServer、Oralce可先采用默认设置,有需要则根据实际情况做相应变动。i. 禁止使用存储过程、触发器、函数、视图、事件等高级功能。j. 数据库设计尽可能的遵循关系数据库范式。k. 设计过程中要考虑尽可能减少后面程序编写时查询的复杂度l. 每张表必须有只用来标识唯一的主键,主键为UUID,统一命名为id,统一为char(32)类型。m. 现阶段暂时不考虑逻辑删除,仍旧使用物理删除。n. 对于中小型项目,数据库设计过程中无需过多的考虑性能、安全的问题。o. 不同的关系型数据库在字段类型的具体化上差异较多,但具体化的字段类型再多,无外乎这几种:字符、数字、日期、二进制。p. 表中应该尽可能避免可为NULL的列,且尽可能显示设置默认值,尤其是被索引的列。q. 如果数据库中某个字段有默认值,在程序开发过程中,对应实体类的属性应该设置同样的初始化值才合理。r. 禁止使用float、double类型,建议使用decimal替代。s. float:浮点型,含字节数为4,32bit,数值范围为-3.4E38~3.4E38(7个有效位);double:双精度实型,含字节数为8,64bit数值范围-1.7E308~1.7E308(15个有效位);decimal:数字型,128bit,不存在精度损失,常用于银行帐目计算。(28个有效位)t. decimal(a,b) ,a指定指定小数点左边和右边可以存储的十进制数字的最大个数,b指定小数点右边可以存储的十进制数字的最大个数。最大精度38。 u. MySQL的decimal对应于Oracle的number,数据类型的精度:number(p,s) ,p: 1---38, s:-84---127。s代表的是小数位数,p代表的是总位数(整数位数和小数位数)。v. 数据库Oracle服务端的exp.exe工具远程导出源数据库,导出导入命令:cd D:\app\bsc\product\12.1.0\dbhome_1\BIN\
exp origin_username/origin_password@origin_tnsname file=C:\Users\Administrator\Desktop\.dmp owner=origin_username
imp target_username/target_password@target_tnsname file=C:\Users\Administrator\Desktop\.dmp ignore=y full=y statistics=none
w. 要求日期时间类型的字段,尽可能精确到时分秒,用datetime类型。x. 字典编码字段,之前在SQLServer中设计数据库时统一使用char(2)类型,Oracle数据库中统一使用number(2),在MySQL中统一使用tinyint(2)。y. 统一命名为remark,字段类型为varchar(200),最多100个中文字符。z. 推荐统一使用int(10)做为所有表中的排序字段类型。aa. 对于表的注释,要求简单明了,先说明表中文名称,句号分隔,然后跟功能说明,无需特别说明的,则只说明中文名称即可。同时,为了最终生成代码注释的可读性,不允许在说明中出现“表”字眼。bb. 主键字段,无须特别注释,注释就两个字:主键。cc. 外键字段注释:` applicant_doctor_id` char(32) DEFAULT NULL COMMENT '申请医生。外键,引用医生表(doctor)的主键(id)。理论上可填多个,以“|”分隔'。
` applicant_doctor_name` char(32) DEFAULT NULL COMMENT '申请医生。名称,和医生表(doctor)的医生名称字段(name)对应。理论上可填多个,以“|”分隔'。
dd. 字典字段注释:`status_code` varchar(5) DEFAULT NULL COMMENT '转诊单状态。编码,对应数据字典表(dictionary)中的编码字段(code)。目前先定义6个状态:01 已提交,02 已取消,03 已审请,04已安排,05 已拒绝,06 已结束。03是向HIS系统执行审请,04是HIS系统已安排入院日期,下转诊时这两个字段没有区别。'
`status_text` varchar(50) DEFAULT NULL COMMENT '转诊单状态。文本,对应数据字典表(dictionary)中的字典项名称字段(name)。目前先定义6个状态:01 已提交,02 已取消,03 已审请,04已安排,05 已拒绝,06 已结束。03是向HIS系统执行审请,04是HIS系统已安排入院日期,下转诊时这两个字段没有区别。'
ee. 普通字段注释:`bed_id` varchar(50) DEFAULT NULL COMMENT '入院床位号。HIS系统安排并反馈的入院床位号,如果是下转诊,此部分由医生手动填写'。
ff. 五种约束类型:唯一性和主键约束、外键约束、检查约束、空值约束、默认值约束,对应五大关键词,UNIQUE和Primary Key, Foreign Key, CHECK, NOT NULL, DEFAULT。本规范中要求,除检查约束外,其余四种都要在数据库中加强约束,同时,程序也会根据数据库中约束的设置做相应处理。gg. 当数据量达到一定程度,仅通过程序优化对性能提升有限时,可以考虑同时对数据库进行调校,这时会优先考虑建立索引。提到的几个注意点:索引外键、索引经常GROUP BY、ORDER BY的字段、不要索引blob/text字段、不要索引小型表、索引多了影响插入删除速度、在条件表达式中经常用到的不同值较多的列上建立检索。hh. 对于并发编辑目前唯一可行的方法,还是在数据库中加入一个锁标识字段。ii. 优化操作日志(OperationLog)表的设计和存储(优先考虑Hbase或OB),来代替单独历史表的设计。jj. 大数据分析可视化平台,针对只有分析结果没有源数据的部分可尝试单独存储成XML数据,或者就是用非关系数据库存储。kk. 在建表时的字段默认排列顺序也要注意。三 命名规范1、引言在前面提到过,数据库设计过程中表、字段等的命名规范也算是设计规范的一部分,但因为牵涉的内容较多,所以将其单独列出。不过设计规范更多的是为了确保数据库设计的合理性、为了项目最终的协调稳定性,而命名规范则更多的是为了确保设计的正式和统一。公正的讲,数据库中表字段等等以什么样的方式命名、取具体什么名字,并不会直接影响到项目的稳定性,不是说叫黑猫项目就是正常的,叫白猫就运行异常了。制定规范的直接目的是约束设计行为,最终目的是确保设计的合理统一。规范虽然是有丰富项目经验的人制定的,但维护的却不是某个人的意志,而是项目的意志,因为遵守此规范对项目是好的有利的,此规范才有意义。所以规范是为了项目利益最大化而在团队人员中形成的一种约定(貌似约定的英文单词Convention本身就有规范的意思),所有参与设计的人员都要遵守此约定,所有参与开发的人员都会依此约定解读设计。我们约定,所有的主键统一命名为id,结果有设计人员违反约定将一个非主键字段命名为id,约定被打破,共识也就被打破,设计人员之间、开发人员与设计人员之间的沟通就出现了隔阂。设计规范更多的是为了合理,命名规范更多的是为了统一,团队协作中,统一在某种程度上比局部设计开发的好坏更重要。违反了约定,局部设计开发的再好,反而可能影响到项目整体的稳定协调。约定优先于配置(Convention Over Configuration)。在“设计规范”中提到过一些命名规范,也详细讲述了表、字段的类型、注释等属性的设置,为什么要求主键统一命名为id、统一为char(32)类型,为什么要求浮点型数值统一为decimal类型?我们希望团队中所有人看到设计成果,一眼就可以明白这个字段是做什么的、代表的含义是什么,可以但不止于见名知意。再者,当前的开发模式,前后端代码及数据库文档、程序文档、接口文档等等大都是由工具生成,而其最底层的依据就是数据库,表、字段的命名注释同时会影响到工具生成的文档、代码中的类属性方法甚至是前台页面的命名注释,数据库设计命名的规范关系到整个项目的规范。命名规范会分四个大模块来介绍:基本规范、名大小写、具体规范、特别说明,各大模块下面有的会有子模块特别说明。2、基本规范A.可用字符数据库、表、字段等所有名称的可用字符范围为:A-Z,a-z, 0-9 和_下划线,除此外不允许使用其它字符作为名称。数据库及表名均不允许出现数字,字段名除非特殊情况不允许出现数字。在前面介绍关系范式时曾提到过一个破坏范式的例子:平时的多图片上传功能,可能只设计一个字段存储图片名称,这样字段值中就会包含多个图片的名称,里面用|或其它符号分隔。像这种情况,其实也可以设计成三五个字段image_name1、image_name2、image_name3……分别存储,然后限制可上传图片个数,这就是字段名中可出现数字的特殊情况——虽然也不建议这样设计或取名。B.命名方式数据库、表、字段等所有名称使用英文单词或英文短语或相应缩写,禁止使用汉语拼音,且均使用单数名,例如:对存储客人信息的表命名为customer而不是customers。名称应该清晰明了,能够准确表达事物的含义,遵循见名知意的原则。Oracle表、字段等名称统一使用大写,单词间用_下划线分隔;SQLServer数据库、表等名称采用Pascal命名法,字段名称采用Camel命名法,大小写字母混排;MySQL数据库、表、字段等名称统一使用小写,单词间用_下划线分隔。至于为何这样规定,下一个模块会有详细介绍。Oracle相对特殊,通常的操作顺序是,先创建数据库实例,然后创建表空间,然后创建用户并设定此用户的默认表空间,最后在此用户下建表。多数情况下我们都是只建一个实例,然后在此实例下建不同的表空间、不同的用户,根据不同的用户来区分不同的库。关于

我要回帖

更多关于 不好好背单词的结果 的文章

 

随机推荐