当前位置: 首页 > 后端技术 > Java

一篇搞定关系型数据库设计要领,值得收藏!

时间:2023-04-01 17:58:16 Java

摘要本文讨论了关系数据库设计相关的一些内容,涉及关系模型、表结构设计等,并以学生选修课的形式描述了设计过程。在尽可能清楚地说明设计要点的前提下,简化设计内容。本文基于MySQL数据库,适合有一定关系数据库基础的人阅读。Entity-RelationshipModel(E-R)首先,什么是E-R数据模型?这是为了什么?E-R模型在将现实世界中事实的意义和相互关系映射到概念模式方面非常有用,因此,许多数据库设计工具都利用了E-R模型的概念。E-R模型采用的三个主要概念是:实体集、关系集和属性。实体:实体是一个“事件”或“对象”,可以区别于世界上的其他对象。例如,学校中的每个学生,学生选修的每门课程都是一个实体。属性:属性是实体集的每个成员都具有的描述性属性。例如学生的姓名、学号等。实体集:实体集是具有相同类型和属性的实体的集合,例如学校的所有学生、学生修读的所有课程等。关系:关系是多个实体之间的关联。例如,小明选修了中文课。关系集:关系集是同类关系的集合。例如,学生所修课程的集合。知道了E-R数据模型的作用之后,我们来绘制学生选修课的E-R图。其中,(学号、姓名、年龄、性别)为学生属性,(年级)为选修关系属性,(课程编号、课程名称、学分)为课程属性。学生和课程之间是多对多的关系,即一个学生可以选择多门课程,一门课程可以被很多学生选修。关系表设计从上面的E-R图我们可以一目了然的看出它们之间的联系,那么如何设计关系模式呢?我们要知道,关系数据库设计的目的是为了生成一组关系模式,方便我们获取信息,而不是存储不必要的冗余信息。为了方便我们实现这个目标,范式设计应运而生。Boyce-Codd范式我们知道令人满意的范式之一是Boyce-Codd范式(BCNF)。如果对于F+中形式为α→β的所有函数依赖,其中α?R和β?R,至少满足以下定义之一:α→β是平凡的函数依赖(即β?α)。(一般来说,讨论平凡的函数依赖是没有意义的,讨论的是非平凡的函数依赖,即β??α的情况)α是模式R的超码。考虑以下关系模式及其对应的函数依赖关系:Student=(StudentID,Name,Age,Gender)StudentID→NameAgeGenderCourse=(CourseID,CourseName,Credit)CourseID→CourseNameCreditElective=(StudentNo.,课程号,年级)学号,课程号→年级以上模式均属于BCNF。以第一组关系模式为例,对student唯一非平凡的函数依赖,箭头左边是学号,学号是模式的一个candidatekey(candidatekey属于超级代码的一个子集),而不破坏BCNF定义。事实上,并不是每个BCNF都能维护函数依赖,例如:Banker-schema=(branch-name,customer-name,banker-name)表示一个客户在某一个分行有一个银行客户经理。它需要满足的函数依赖集F为banker-name→branker-namebranch-namecustomer-name→banker-name显然,Banker-schema不属于BCNF,因为banker-name不是supercode。我们可以将其分解得到BCNF,如下所示:branch-name,不维护branch-namecustomer-name→banker-name的依赖关系。第三范式是当我们不能同时满足以下三个设计目标时:BCNF。无损连接。保持功能依赖。我们可以抛弃BCNF,接受相对较弱的第三范式(3NF)。因为3NF总能找到一个无损连接并保留依赖关系的分解。具有函数依赖关系的关系模式R,即F,属于3NF,只要F+中所有形式为α→β的函数依赖,其中α?R和β?R,至少有一个以下定义成立:α→β是一个平凡的函数依赖(即β?α)。α是模式R的超代码。β-α中的每个属性A都包含在R的候选键中。回到Banker-schema示例,我们已经看到分解无法将关系模式转换为BCNF,同时保持依赖关系和无损连接,但模式属于3NF。在Banker-schema中,候选键是{branch-name,customer-name},所以只有banker-name没有包含在Banker-schema中。α→banker-name形式的非平凡函数依赖都具有{branch-name,customer-name}作为α的一部分。由于{branch-name,customer-name}是候选键,符合3NF的定义。每个BCNF都属于3NF,因为BCNF的约束比3NF更严格。存储引擎的选择一旦确定了关系模式,基本的数据库表结构就确定了,接下来就是表结构的详细设计。这里我们从存储引擎开始。MySQL提供的各种存储引擎是根据不同的用例设计的。的。下表概述了MySQL提供的一些存储引擎。最常用的两种存储引擎:MyISAM和InnoDB。MyISAM:在MySQL5.5.5之前,MyISAM被用作MySQL的默认存储引擎。InnoDB:MySQL5.5.5之后,InnoDB作为MySQL的默认存储引擎。另外,关注公众号Java技术栈,后台回复:面试,可以拿到我整理的MySQL系列面试题及答案,很全。如何选择?选择标准:根据应用的特点选择合适的存储引擎。对于复杂的应用系统,可以根据实际情况选择多个存储引擎进行组合。但要注意组合使用的缺点:InnoDB和非InnoDB存储引擎组合的比较,只使用InnoDB存储引擎可以简化备份和恢复操作。MySQLEnterpriseBackup对使用InnoDB存储引擎的所有表执行热备份。对于使用MyISAM或其他非InnoDB存储引擎的表,它执行“热”备份,数据库继续运行,但在备份过程中不能修改表。以下是常用存储引擎的适用环境:InnoDB:事务性业务场景的首选。MyISAM:大多数非事务性业务场景。内存:数据保存在内存中,可以提供极快的存取速度。(个人认为可以改用Redis等NoSQL数据库。)选择好字符集的存储引擎后,字符集就确定了。更改字符集时将付出高昂的代价。如何选择?建议在充分满足应用当前和未来发展的前提下,尽量使用小字符集。应该是,较小的字符集意味着节省空间,减少网络传输的字节数,同时由于存储空间小间接提高了系统的性能。不同的数据库有不同的字符集应用级别,分别是服务器级别、库级别、表级别和字段级别。通常推荐使用库级别或者表级别。因为库级别或者表级别在保持灵活性的同时兼顾了数据之间字符集的统一,这样可以省去很多开发处理字符集的麻烦。数据类型的选择选择原则前提:使用合适的存储引擎。选择原则:为了优化存储,在所有情况下都应尽量使用最精确的类型。定长和变长char和varchar下面举例说明两者的区别:请注意,上表最后一行的值只适用于不使用严格模式的情况;如果MySQL运行在严格模式下,超过列长的值将不会被保存,会出现错误。从CHAR(4)和VARCHAR(4)列检索的值并不总是相同,因为检索时尾随空格从CHAR列中删除。以下示例说明了差异:mysql>CREATETABLEvc(vVARCHAR(4),cCHAR(4));QueryOK,0rowsaffected(0.01sec)mysql>INSERTINTOvcVALUES('ab','ab');QueryOK,1rowaffected(0.00sec)mysql>SELECTCONCAT('(',v,')'),CONCAT('(',c,')')FROMvc;+---------------------+--------------------+|CONCAT('(',v,')')|CONCAT('(',c,')')|+--------------------+---------------------+|(ab)|(ab)|+--------------------+----------------------+1rowinset(0.06sec)对于InnoDB数据表,内部行格式不区分定长列和变长列,所有数字化的行都使用指向数据的头指针指向列值,所以本质上,使用一个固定长度的CHAR列不一定比使用可变长度的VARCHAR列更好。因为,主要的性能因素是数据行使用的存储总量。对于占用的空间,CHAR总是大于等于VARCHAR,所以使用VARCHAR来尽量减少行数据存储的总量,从而降低磁盘I/O的频率。当text和blob使用text或blob类型的字段时,为了获得更好的性能,需要注意以下几点:在进行大量的delete和update操作后,会出现很多“洞”,而你需要定期优化表进行碎片整理;避免查询大文本和blob。查询大文本和blob将减少页面上可以加载的数据量并增加磁盘I/O压力。将文本和blob分隔到单独的表中。这会将原始表中的数据列转换为更短的定长数据行格式,这是非常有用的。浮点数和定点数在MySQL中,float和double是浮点数,decimal是定点数。浮点数的优点:在一定的长度下,浮点数可以表示更大的数据范围。浮点数的缺点:精度问题。友情提示:金钱交易慎用浮点数!!!整数MySQL支持SQL标准整数类型INTEGER(或INT)和SMALLINT。作为标准扩展,MySQL还支持整数类型TINYINT、MEDIUMINT和BIGINT。下表显示了每种整数类型所需的存储空间和范围。索引设计设计原则搜索到的索引列不一定是要选择的列。最适合建立索引的列是出现在WHERE子句中的列,或者是在join子句中指定的列,而不是出现在选择列表中SELECT关键字之后的列。使用唯一索引。索引在具有唯一值的列上效果最好,在具有许多重复值的列上效果最差。使用短索引。如果在字符串列上建立索引,则应指定前缀长度。例如,如果您有一个CHAR(200)列,如果大多数值在前10或20个字符内是唯一的,则不要索引整个列。利用最左边的前缀。每个额外的索引都会消耗额外的磁盘空间并降低写操作的性能。不要超过索引。考虑对列进行比较的类型。如果你是在对列做函数操作,索引它就没有意义了。示例针对上述学生??选课E-R图,给出设计结果及说明:表1-1学生信息表(Student)表1-2课程信息表(Course)表1-3选课结果表(SC)Student名字长度为40,这里也考虑外国人;Student中的gender定义为枚举,主要是因为枚举意义简洁;Student中不存储年龄,存储出生日期是因为年龄不是静态的。并且能够按出生日期正确计算。SC分数使用double而不是decimal,主要是因为分数不需要那么高的精度。在SC中(sno,cno)被用作联合主键而不是独立主键。由于现阶段markdown无法合并行,所以无法编辑。参考资料(美国)AbrahamSilberschatz等人。数据库系统概念。北京:机械工业出版社,2012MySQL5.7参考手册[eimhe.com]网易技术部MySQL中文资料。