数据库系统工程师
今天先完成前2个的知识点。
1.形参和实参
首先先说一下他们的定义:
形参:全称为“形式参数”,从字面意思上可以看出它是一个形式上的参数,相当于一个走过场的、不是实际存在的虚拟变量。函数中定义的变量就是形参。
实参:全称为“实际参数”,同样的,从字面意思可以看出来这是一个实际存在的参数,既然实际存在,那必须要有一个确定的值,不管表达式,还是常量、变量或函数,无论他是什么类型,在调用他的时候,都必须有一个具体的值,实参才能值传递给形参。
例子:
int add(int a, int b) {} 这其中的a,b就是形参。当主调函数调用该函数传入的参数则是实参。
接下来说说他们的区别:
1、形参是出现在函数定义中,当出了这个函数体的范围时,即被调函数结束返回主调函数时,则不能再被使用了,因为当他被调用时才分配内存单元,调用结束时即刻释放资源。同样的,当实参将值传递给了形参,在被调函数中,实参也不能被操作。
2、函数调用中数据的传递只能是单向的。且由实参传递给形参,不能形参反向传递值给实参。因此在被调函数中无论形参怎么被“蹂躏”,实参都不会有任何影响(该项只限于实参和形参不是指针类型)。
3.当实参和形参为指针类型时,传递的是内存地址,即在被调函数中使用的是实参本色,此时形参发生改变会导致实参的值也发生改变。
2.范式
首先呢,范式分为:第一范式、第二范式和第三范式三种。层层递进,一层比一层严谨。
要区分一个关系模型为哪种范式,首先要判断该关系的每个字段是否是不可再分割的。如果这个条件都不满足,那么它将不是任何一个范式。
说明一下,在任何一个关系数据库中,第一范式是最低要求,数据库不是excel,不能对单元格进行多个拆分,如果连第一范式都无法满足,则这个表无法成型,就不是关系数据库。
其次,要分清一个关系模型属于哪个范式,要先理解3个函数依赖概念,分别是完全函数依赖,部分函数依赖和传递函数依赖。
函数依赖的定义是:当X值确定,则Y值必确定,称作Y函数依赖于X
完全函数依赖:如果X只是一个属性,则Y函数依赖X的同时也是完全函数依赖。当X是一个属性组(比如复合主键),无论X的哪一个真子集确定,都无法确定Y的值,则称作Y完全函数依赖于X。
部分函数依赖:X是一个属性组,并且当X的某一个真子集确定时,Y的值也随之确定,且Y依赖于X。再称作Y部分函数依赖于X。
传递函数依赖:Y函数依赖于X,Z函数依赖于Y,并且X、Y没有任何依赖关系,且Y不是X的真子集,则称作Z传递函数依赖于X。
(通俗一点……X确定了Y,而Z又由Y来确定,然而X、Y又一毛钱关系都没有,所以最后Z的值,还是需要通过X来确定的Y的值,随后再通过Y确定。)
第一范式
这个表格1最基本的,随处可见,这就不满足第一范式,因为销售字段是可再分割的,当其改为表格2,则满足了第一范式的要求。
学生姓名 | 课程 | |
课程名 | 成绩 | |
... | ... | ... |
学生姓名 | 课程名 | 成绩 |
... | ... | ... |
第二范式
第二范式是在第一范式的基础上,再进行一次划分,消除了非主属性对码的部分函数依赖,使得所有属性完全依赖于主键。
还是用表格2来说,这个表格属于第一范式,但为什么不属于第二范式?
原因是因为它没有主键,没有一个属性确定之后,能精确到一笔记录。如表格3,确定学生姓名为“张三”之后就能精确到哪一条记录了吗?显而易见是并不能的,这就没有达成第二范式的要求,没有让所有的属性都完全依赖于主键。可以添加一个列属性“编号”,这样就可以满足第二范式。因为编号唯一,当编号确定,则可以精确定位到哪一条数据。
学生姓名 | 课程名 | 成绩 |
张三 | mysql | 80 |
张三 | ORACAL | 80 |
李四 | MySQL | 80 |
... | ... | ... |
编号 | 学生姓名 | 课程名 | 成绩 |
1 | 张三 | MySQL | 80 |
2 | 张三 | ORACAL | 80 |
3 | 李四 | MySQL | 80 |
... | ... | ... | ... |
其次我们再来说说,如果精确的判定一个关系模型是否为第二范式。
第一步:找出关系中的所有的码(表中可以唯一确定一个元组的某个属性(或者属性组),如果有多个,则都成为候选码)。
第二步:除去那些码,判断剩下的所有非主属性,是否对码完全函数依赖,如果是,则符合第二范式,反之则不是。
第三范式
第三范式消除了非主属性对码的传递函数依赖。
例如表格5,学号能唯一确定一个元组,但是元组中的每个非主属性就没有依赖于其他非主属性了吗?
显然是没有的,学号是单个关键字,所以不存在传递函数依赖,即满足第二范式,但是他一定满足第三范式了吗?
第三范式解决的问题是第二范式带来的插入、删除异常、数据冗余度大河修改复制等问题。表格5有没有数据冗余呢?
从数据上来看,关系中的(所在系,系名字,系地址)是存在一定的冗余的,且所在系依赖于学号,而系名字和系地址是依赖于所在系的,由此可以得出,系名字和系地址,存在传递函数依赖。
改成表格6和表格7,则满足第三范式。
学号 | 姓名 | 所在系 | 系名字 | 系地址 |
1 | 张三 | Computer | 计算机系 | 教学楼3号 |
2 | 李四 | Computer | 计算机系 | 教学楼3号 |
3 | 王五 | Math | 数学系 | 教学楼2号 |
... | ... | ... | ... | ... |
学号 | 姓名 | 所在系 |
1 | 张三 | Computer |
2 | 李四 | Computer |
3 | 王五 | Math |
所在系 | 系名字 | 系地址 |
Computer | 计算机系 | 教学楼3号 |
Math | 数学系 | 教学楼2号 |
总结一下,第二范式消除了部分函数依赖,第三范式消除了传递函数依赖。
说个题外话,反范式。
数据库的范式设计是为了减少数据冗余,减少数据的插入、修改和删除异常,让数据各司其职,分工更加明确,数据组织更加和谐。
但是这样在开发过程中一定就更方便使用了吗?
当数据库设计严格按照第三范式来设计时,表会越来越多,而表多带来的问题则是查询时要不断的连接多个表,增加了查询语句的复杂度和数据库的查询性能。第三范式可以说是牺牲了性能(时间)来换取空间。
反范式就是不遵守范式,增加一些冗余,来提高查询速度。但也并不是不能完全不遵守范式,毕竟这个东西设计出来并流传下来,好处是毋庸置疑的,让关系数据库更加稳定。
所以个人觉得,开发过程中,如果一些数据频繁查询,且不在同一张表,可以考虑反范式设计,即在第三范式的基础上,适当的添加一些冗余,这样无论是数据结构还是可读性都取了一个折中点。
举个例子:有3个关系模型分别是客户、商品和销售记录
客户(客户编码,客户名,手机号,地址)
商品(商品编码,商品名,价格)
销售记录(流水号,客户编码,商品编码,销售数量,销售时间)
当我们要查询某个时间,各客户购买的商品记录,所编写的SQL语句如下:
SELECT C.客户名,B.商品名
SUM(A.销售数量) AS 购买总数
SUM(A.销售数量 * B.价格) AS 消费金额
FROM 销售记录 A
left join 商品 B ON A.商品编码=B.商品编码
LEFT JOIN 客户 C ON A.客户编码=C.客户编码
WHERE TO_CHAR(A.销售时间,'YYYY') = 2018
GROUP BY A.商品编码,A.客户编码,C.客户名,B.商品名
这样一看似乎并不是多复杂,但如果表更多了呢?多了一个进货信息表要查询利润呢?多了一个客户会员制度要查询该客户下个月的打折折扣呢?是不是感觉一瞬间就麻烦了起来。
所以这3个关系,如果能在销售记录关系中加以修改,增加适当的冗余不再遵循3范式。
销售记录(流水号,客户编码,客户名,商品编码,商品名,销售数量,销售时间)
这样我们从这一个表格,就能算出以上所需要的数据,不再需要连接商品和客户两个表。
当然了,具体的反范式设计还是需要根据实际情况来选择,不能一味的为了追求查询效率而乱添加冗余,毕竟提高数据库的性能,并不只是靠反范式,还有很多方法,比如索引,比如视图,比如oracle的parallel模式等等。
相关阅读
Oracle 11g 创建数据库详细步骤 方法/步骤 ①. 按住键盘上Windows键,打开开始菜单,找到Database Configuration Assitant并打
触发器的概念触发器是一种特殊的存储过程,它被分配给某个特定的表。当对这个表进行插入、更新或删除操作时,自动调用触发器执行触发
提到空间数据库,首先想到的一定是Esri公司的ArcSDE(SDE即Spatial Database Engine,空间数据库引擎),ArcSDE主要支持的数据库包括Oracle
在做数据库的查询过程中,使用方法ExecuteReader,其返回结果为MySqlDataReader,由于参考的信息有误,走了好长时间的弯路,记录下来; stri
概念结构设计:将需求分析得到的用户需求抽象为信息结构(即概念模型)的过程。 一、概念模型 在需求分析阶段所得到的应用需求应