引子:
1、数据库有三级模式。
2、物理独立性:数据在磁盘上存储。
3、逻辑独立性:表的逻辑设计。
4、两级映射,表的逻辑不会其物理存储逻辑。
5、视图层:dba给用户展示的部分内容。
一 数据模型
1、层次数据模型,树
2、网状数据模型
3、关系模型
3.1 基本结构就是表。现实世界中的实体用表来表达,实体之间的联系,也用“表”来表达。
3.2 查询的是表,查询出来的还是表,因为它是这样一个封闭的空间,所以可以用数学的方法,即关系代数中的集合论,来研究数据。
3.3 sql语法,就是以关系演算为基础的,它不需要推理过程,关系代数则用来推理数据如何查出来的过程。
3.4 表里每一行,叫作元组,一个表中的所有元组,组成一个集合。
3.5 sql是非过程化的。非过程化是指我告诉数据库我要什么,数据库给我查出来,而我不用关心它是怎么查出来的。过程化是要写代码,去执行,才能把数据查出来,层次模型和网状模型就是过程化的查询。
3.6 软连接,就是id,通过id能找到一条数据。而层次和网状,在面对一对多,多对多等关联关系时,存储的是对方的物理地址,这叫硬连接。
3.7 关系数据模型在70年代就取代了层次和网状成为主流,但并不意味着人们就对它满意。以上三种属于传统数据模型,他们也有很多缺点,比如关系数据模型语义不清,如果没有文档,一个新人是看不出来表与表之间的联系的。
后来有人提出:
3.7.1 er数据模型,结果没发展起来,反而成了描述数据关系的er图。像关系数据模型语义不清,用er图来表示就很清晰了,省写文档。er图是需求分析和数据库设计阶段用的。
3.7.2 面向对象数据模型,与关系相比,它突破了一范式限制。也没发展起来。
二 SQL
1、数据模型是DMS的核心
2、DBMS提供的用户接口:查询语言,访问工具(GUI),api(给代码调的,如jdbc),类库(如给java、c++编写的)
3、sql,原指结构化查询语言,1986年改叫标准查询语言,还是简称sql,它有四个子集。
sql中的关键字:Base table, View, Data type supported, NULL, UNIQUE, DEFAULT, PRIMARY KEY, FOREIGN KEY, CHECK(Integration Constraint)
四 sql语句讲解
1、from后跟几张表,底层(DBMS)就会做几张表的笛卡尔乘积(假如a表三个字段,b表四个字段,乘积出来就是七个字段,还有所有的数据)。然后根据where条件排除不要的数据。笛卡尔乘积会出现很多无用数据,效率低,后面会讲如何优化。
不同的数据库产品要注意这些别名、模糊查询等小方法的区别。
select s.age, age1 = s.age-5,2*s.age as age2 from sailors s where s.sname like 'b_%b';
2、查询时,善用集合思维,比如union取并集,intersect取交集等。
3、in与exists,子小主大用in,相反用exists,区别详解点我
4、group by 和 having,先用where条件筛选数据,再用group by 的条件分组,然后再用having把每组的数据再筛选。
如果select后还有聚合函数,那它将在group by分组后,在每个组里执行聚合函数,比如count,min,都是计算本分组的总数,最小值。
语法规定,select、having后面的内容,必须是group by内容的子集(当然聚合函数除外)。
SELECT S.rating, MIN(S.age) FROM Sailors S WHERE S.age > 18 GROUP BY S.rating HAVING 1 < ( SELECT COUNT(*) FROM Sailors S2 WHERE S2.rating = S.rating)
其他语法:
CAST expression, CASE expression, Sub-query, Outer Join, Recursion
5、cast,用来赋值。
SELECT name ,rank, CAST (NULL AS Varchar(20)) AS subject, CAST (NULL AS Integer) AS enrollment FROM teacher-only
6、case,case某个字段,查出值;或直接case when...,如:
SELECT sum(CASE WHEN type = 'chain saw' THEN accidents ELSE 0e0 END) / sum(accidents) FROM Machines;
7、子查询可以是一个范围,亦可以是一个值(它可以出现在select后面)
8、一段子查询需要用多次,可以将它定义为公共表表达式(就是下面要说的临时视图),相当于一个临时视图。用with定义,写在前面
WITH payroll (deptno , totalpay) AS (SELECT deptno ,sum(salary)+ sum(bonus) FROM emp GROUP BY deptno) SELECT deptno FROM payroll WHERE totalpay = (SELECT MAX(totalpay) FROM payroll);
9、递归查询。emm...用到再去详细了解吧,但老师解决问题的思路很号,把复杂查询,简化成一个对临时表的查询筛选!
sql的重点还是查询呀
10、视图
分为普通视图、临时视图(如with)。
真正存储在磁盘上的表,叫做基表,而视图所查出的表叫虚表,虚表数据不落磁盘,磁盘上只存储视图的定义(新建个数据库时,视图都被存在其自带的系统表里),用的时候临时查出来数据,将其看作一个表。
视图可以用作权限控制,比如某些数据不想给人看,就可以创建个视图,然后让这人看这个视图里的数据就好了。
需要做视图更新时,要看它适不适合做。
General view的定义存在数据库里,temporary view连定义也是临时的,不存数据库
11、数据库如何与语言配合
1)嵌入式sql:比如sql写到c语言代码里,通过预编译将sql与代码分开,然后调用c的函数库执行
2)api:对sql的函数调用,定义一套规则,mysql、oracle等不同厂家都去实现这套规则。如odbc、jdbc
3)直接用编程语言的类库去调。
数据库的原理,一直没有变,而嵌入sql,api和类库调用只不过是为了让人用起来更方便而已,但本质却没有变化。
查询时,如何把查询出的集合,作为一个新的变量使用呢?用游标。
12、游标
游标用时,就open它,一open,就会执行游标定义的sql,然后返回一个集合,就可以把这个集合,当成是一个文件,然后使用这个游标的名字,就好像在使用这个文件一样,读文件会用指针嘛,与此类似,使用fetch,拿到当前元组的数据,into到你设置的变量里,然后循环,就像放下一个指针的数据,再fetch into,最后数据读完了,会有标志位提示当前的程序设计语言,让他别循环了,然后关闭游标,这一切资源也就被释放了。示例如下:
13、存储过程:
就是一组经常被调用的、要完成某个逻辑的sql,省得每次重复写它了。语句会被dbms编译优化
三 数据库管理系统(DBMS)(本文重点)
1、DMBS实现原理总体架构
1.1一个应用和数据库连接,DBMS的deamon会监听端口,看谁连过来,有人连,就给他建立个线程,让他和dbms通信,如果对方是远程链接,就用socket通信,如果是本地,就用pipe通信,通信只接收sql,返回结果。连接结束了,应用那边要close这个链接,然后这个线程就会被操作系统回收。(这让我想到了,当年jdbc为啥非要session.close,集采的数据库会出现连接满了的情况,就是因为用plsql连的数据库,然后线程没关,线程池就满了。)
deamon只管接人,开线程,别的不管。
1.2 数据库底层的文件存储方式
1.2.1存储的物理方式:硬盘是块状存储,基本单位是1kb/块,磁头每次取数据,至少扫描一个块儿大小。
假如表里一个元组,数据加起来一共100b,则一个块里可以放10个元组(通俗讲就是10条数据),DBMS在查询时,就把每一块的数据读出来,看看里面有没有自己要找的。
1.2.2存储的逻辑方式:常见的关系型数据,其最基本常见的存储方式:
1.2.2.1 堆——随着文件的插入,不停地往其尾巴上堆。它的访问路径就是顺序扫描,扫完了才能查到数据。
1.2.2.2 hash——其文件的hash值,就是其存储地址。
1.2.2.3 索引+堆:对堆文件的某一列,建立b+树索引(非叶节点仅有索引作用,信息存在叶节点,B树与B+树对比)
1.2.2.4 其他:动态hash(普通索引可能分配的空间过小、或者过大,不如动态更高效)、raw disk(自己申请硬盘空间,自己决定物理存储方式,而跳过操作系统的存储方式,这样的目的是:减少磁头寻道时来回移动(这是查询慢的关键),从而提升查询速度。这叫簇集存储,因为它是按照一定顺序存的,所以可以将其看作是个索引)
索引技术分类:
B+ Tree,Clustering index, Inverted file, Dynamic hashing, Grid structure file and partitioned hash function , Bitmap index (used in data warehourse), Others。
总之,关系型数据库用的最多的,就是B+树索引、簇集索引。
2、查询sql在DBMS中如何优化
关系型数据库刚提出时,很多人反对,因为关联查询需要做多个表的笛卡尔乘积,然后逐一笔记,效率太低。但后来关系型数据库成为主流,就是因为它通过查询优化,解决了这个瓶颈。
2.1代数优化:将sql先改写一下,等价、但运算次数少(高效),成为更优的形式。
比如dbms进行语法分析,生成查询树,然后可以根据查询条件先筛选数据,这样可能要关联查询的数据就少了。
2.2操作优化:sql进行具体操作时的优化方法。
一元操作简单,难的是二元操作,就像左连接、右连接这种两表关联查询。
关系型数据库最影响效率的就是联结运算。因为表设计要满足一张表只做一件事,这样就导致查询时需要关联查询,而关联查询需要两个表的笛卡尔乘积,所以很慢。
关系型数据库常用的联结查询优化算法如下:
2.2.1内循环:俩表都取一个块儿,放到内存里,然后一个一个比较。比完这个块继续比下一个块。
2.2.2联结查询时,使用索引:比如两个表关联查询,一个表先把一部分物理块儿,读入内存,然后做投影,看其连接属性(就是外键,即类似join语句里最后的where a.bid=b.id)有多少不同的值,然后用这几个不同的值,去查另一个表的b+树索引(不加索引的话就把表里的每个元组都查一遍,又导致寻道时间增加,而索引就不用),然后匹配索引值,根据索引值,直接拿到那条数据的地址。
所以,索引就是避免了内循环对表的扫描。
如果,刚才说的另一个表的b+树索引的列,重复值数量占总数20%以上,就不适合用索引了,因为你最后匹配索引值,拿到数据地址,因为有重复所以会拿到多个数据,多个数据可能会涉及到硬盘的很多物理块儿,这样取这些数据的寻道时间还是要消耗很多,那么用索引的效果就不明显了。
所以,用索引也不是永远有效。 (索引这一讲在视频数据库管理系统第8课)
2.2.3 hash:在需求分析时,如果两表不用更新,将两表的联结属性,hash一下,然后放到hash文件里,这样查询直接查这个hash文件里的值即可,就不用像上面那样做那么多操作了。
dump,数据库备份数据。可以备份全部,也可以备份每次更新的那部分;现在企业级的做法是备份+日志。这样可以把来不及备份的内容,通过日志,进行补操作,来恢复到离故障点最近的时间。
正如操作系统运行的基本单位是进程,数据库运行的基本单位是事务,事务有四个特点:acid,原子一致隔离持久;如果没用事务,那么dbms会把每条sql当作一个事务运行。
dbms会为每一个事务赋予一个TID,正在操作的事务存到active list表,操作完成的事务放在commit list表。如果遇到断电,有三种情况:
The recovery after failure in this situation ,check two lists for every TID while restarting after failure:
Commit list | Active list | |
√ | delete TID from active list | |
√ | √ | redo, delete TID from active list |
√ | nothing to do |
第一种因为事务还没对数据库操作,所以删了tid就好。
第二种需要检查并对比active list表和commit list表,两表都有数据,就说明事务正要提交就断电了,这时把active list里的事务,操作一下,让它执行完并提交事务,然后将其从active list里删除。(就算此时再停电也没事,继续搬)
第三种,说明事务已经提交了,不用管。
3、DBMS的事务管理,并发控制
3.1数据库里的并发事务冲突,分为两大类:写写冲突(如丢失更新)、读写冲突(如不可重复度,还有脏读属于写读冲突)
3.2、并发控制,控制的就是:运行结果可串行化(n个事务同时给数据库,会有n!个顺序执行结果,dbms的执行结果只要是n!个结果之一就行)。
要保证结果串行化,就要加锁,其原则就是:每个对象上有个锁,并行的事务按照它们抢到锁的顺序,去执行串行化。
四 安全与约束
五 数据库设计
1NF:表中每个属性都是原子的。
2NF:在1NF基础上,消除属性对主键的部分函数依赖得到。
3NF:在2NF基础上,消除属性对主键的传递依赖得到。
精华就四个字:一事一地——一张表只干一件事。
软件工程流程是:需求分析(看对业务理解对不对)——概要设计(画业务实体的er图,不管用什么DBMS)——逻辑设计(根据选的dbms类型,设计具体的表和属性的定义,这一步视图等也要确定,也不用再和用户讨论)
1、实际中的应用:
传统的企业,各部分可能交流不畅,但在信息化管理时,不能再按照传统企业的模式去设计。
比如,多个部门都有自己的员工,不可能以部门为中心,为每个部门设计个员工表,这样表直接就会重现很多重复,而且一个人如果经历过很多部门,它的数据记录起来就会很麻烦。
所以,为企业的数据库设计,除了遵从三大范式,还应该秉承以数据为中心的原则,一个人,就是一个数据,而不是一个部门。
现实中的每一个概念、每一个基本元素,必须来源唯一,责任唯一。看每个属性是否与其他有冲突、混淆、异名同意的现象,真正做到每个属性都是唯一的。
还有个例子:员工表有些隐私信息,不能让人看,于是单独建了个表放这些信息。这样做是不对的,应该建立视图。
总之,要通过需求分析理清——最原子的概念是什么?
仅仅在结构上达到3大范式是不够的。“一事一地”包括每项信息的唯一,要提取出问题的本质,识别出本质上同一概念的信息项。对于表达类似信息,模式相似只是取值不同的表,应尽量合并。考虑到效率、用途等因素,该分开的表还应该分开。结合DBMS内部实现技术,合理设计索引和文件结构,为查询优化准备好存取路径。在结构规范化、减少数据冗余和提供数据库访问性能之间仔细权衡,适当折中。
六 分布式数据库
数据库分割方法:根据查询需要,可以将一个表,根据业务不同, 分割成不同的裂片,分布在不同的节点上。
七 数据库其他领域
数据仓库、数据挖掘:将积累下来的海量数据,进行挖掘,分析,为我们经营决策提供一些支持。
数据仓库是将数据,按照决策分析需求,重新收集起来。它主要做复杂的查询,也不需要数据是最新的。