Database Systems Concepts: Data Models, Transactions, and Query Processing
引言
数据库管理系统 ( DataBase-Management System, DBMS) 由一个互相关联的数据的集合和一组用以访问这些数据的程序组成。这个数据集合通常称作数据库( database),其中包含了关于某个企业的信息。DBMS 的主要目标是要提供一种可以方便、高效地存取数据库信息的途径。
设计数据库系统的目的是为了管理大量信息。对数据的管理既涉及信息存储结构的定义,又涉及信息操作机制的提供。此外,数据库系统还必须提供所存储信息的安全性保证。
在大多数组织中信息是非常重要的,虽然用户界面一般隐藏了背后的数据库细节,但数据库也各行各业广泛的使用。因而计算机科学家开发了大量的用于有效管理数据的概念和技术。这些概念和技术正是本书所关注的。在这一章里,我们将简要介绍数据库系统的基本原理。
数据库系统的目标
在数据库系统系统产生前,和一些不需要那么复杂的数据库系统的时候,人们使用计算机的 文件处理系统 来存储和管理数据,一般使用树状的分类结构以及分类结构中的文件。
使用文件处理系统处理大规模数据有下面的可能的问题
- 数据冗余和不一致:由于创建人的不同,相同的信息可能同时被存储在多个不同位置的不同文件中,这造成了存储空间浪费以及修改不便
- 数据访问困难:在文件处理系统中,想要按照某种预先没有设计的规则选取数据需要数据处理部分手动设计复杂的程序来完成,难以快速实现
- 数据孤立:由于数据冗余与分散导致检索困难
- 完整性问题:由于数据的分散,难以对数据进行各种完整性与规则校验
- 原子性问题:部分操作(尤其是数据的修改)需要同时完成或者同时不完成,这就是原子性,文件处理系统难以支持这一点
- 并发异常:文件处理系统设计只出没有考虑高并发问题
- 权限管理:用户应该只能看到自己被授权的部分,分散数据难以实现权限管理
数据库系统的目标就是解决这些现存的问题
数据视图
分层的数据库设计
优秀的数据系统需要能处理我们在前面提出的问题,其中最重要的一点就是通过多个层次的抽象,让终端用户无需接触那些复杂的计算机系统,从而简化两者之间的交互,把复杂的内容留给专门的维护人员。
一般,我们需要分层进行结构设计
- 物理层:在计算机系统上的存储方式,数据库关系系统将按照某种预设规则将数据在计算机系统上存储。这是数据库的开发与维护人员才关注的内容
- 逻辑层:比物理层更加高的层次,描述了数据中存储什么样的数据以及他们的存储方式。逻辑层用户只关注自己的数据之间的逻辑,至于如何将这种逻辑引入物理层不是他们的工作。这是数据库系统的管理员以及相关员工工作的位置
- 视图层:只描述数据库的一个部分,逻辑层存储了大量的数据,用户并不需要同时使用他们,视图层将逻辑层中的数据提取并且按照预设方式呈现,用户经由此和数据库交互
数据模型
数据模型数据库的的基本结构,他是描述数据,数据联系,数据语义以及数据约束的一系列的概念工具的集合。
数据模式直接指导我们如何设计逻辑层,间接影响我们的物理层的设计,直接影响我们和数据库管理系统的交互方法以及视图层的设计。
下面是常见的几种数据模型
- 关系模型(relational model) :关系型模型使用表的集合表示数据与数据间的联系。使用关系模型的数据库由大量的表组成,每个表包含特定类型的记录。每个表由大量的列组成,存储我们需要的数据,并且使用部分列的表示让我们可以将多个表联系起来构成整体
- 实体-联系模型(entity-relationship model):实体-联系模型基于对现实世界的认识而形成,是数据库设计的时候很重要的一部分
- 基于对象的模型(object-based data model):面向对象的程序设计已经称为了软件开发的主流,基于对象的模型是ER模型增加了封装与方法后的产物,将面向对象的思想与关系数据模型结合起来了
- 半结构化数据模型(semistructured data model):半结构化模型也是对关系型模型的继承,但是我们允许使用各种半结构化的数据,XML是其中的其中的典型
我们在后面的研究中主要关注 关系型模型中的 SQL 语言,为了从头建立一个完整的关系型数据库研究 E-R 模型。并在有条件后研究 XML,这种现代互联网中广泛存在的语言。
数据库设计
高层的数据模型为数据库设计者提供了一个概念框架,去说明数据库用户的数据需求,以及将怎样构造数据库结构以满足这些需求。因此,数据库设计的初始阶段是全面刻画预期的数据库用户的数据需求。为了完成这个任务,数据库设计者有必要和领域专家、数据库用户广泛地交流。
下一步,设计者选择一个数据模型,并运用该选定的数据模型的概念,将那些需求转换成一个数据库的概念模式。
从关系模型的角度来看,概念设计阶段涉及决定数据库中应该包括哪些属性,以及如何将这些属性组织到多个表中。前者基本上是商业的决策,在本书中我们不进一步讨论。而后者主要是计算机科学的问题,解决这个问题主要有两种方法:
- 一种是使用实体-联系模型
- 另一种是引人一套算法(通称为规范化),这套算法将所有属性集作为输人。生成一组关系表
最后,我们需要将设计好的关系模型形成在逻辑层的结构,并且建立其对应的物理层结构,在这个过程中过程我们可以要求数据库管理系统拥有一些我们想要的特性。
实体-联系模型
实体联系( E-R)数据模型使用一组称作实体的基本对象,以及这些对象间的联系。实体是现实世界中可区别于其他对象的一件“事情”或一个“物体”。例如,每个人是一个实体,每个银行账户也是一个实体。
数据库中实体通过属性(attribute)集合来描述。它们也组成了实体集的属性。在很多情况下,我们用额外的属性 ID 来唯一标识标示(因为可能存在两个实体属性都一样,因此需要标示)。
联系( relationship) 是几个实体之间的关联。例如,member 联系将一位教师和她所在的系关联在一起。同一类型的所有实体的集合称作实体集( entity set),同一类型的所有联系的集合称作联系集( relationship set)。
数据库的总体逻辑可以用ER图来标示,最常用的标示方式为
- 实体集用矩阵表示,包含这个实体的名字以及其拥有的属性
- 联系用联系两个实体的菱形表明,联系名在菱形内部

规范化
设计关系数据库所用到的另外一种方法是通常被称为规范化的过程。它的目标是生成一个关系模式集合,使我们存储信息时没有不必要的冗余,同时又能很轻易地检索数据。
这种方法是设计一种符合适当的范式( normal form)的模式,为确定一个关系模式是否符合想要的范式,我们需要额外的关于用数据库建模的现实世界中机构的信息。最常用的方法是使用函数依赖( functional dependency)
我们一般使用规范化检验我们使用ER模型构建的数据库,看看其联系和属性是否合理,有没有信息重复和失去表达某种信息的能力
数据库体系结构
数据库系统的体系结构很大程度上取决于数据库系统所运行的计算机系统。数据库系统可以是集中式的、客户/服务器式的(一台服务器为多个客户机执行任务);也可以针对并行计算机体系结构设计数据库系统;分布式数据库包含地理上分离的多台计算机。
今天数据库系统的大多数用户并不直接面对数据库系统,而是通过网络与其相连。因此我们可区分远程数据库用户工作用的客户机( client) 和运行数据库系统的服务器( server)。 当然在初步使用数据库的时候,我们是往往会把服务器和客户机放在一台电脑上
数据库的用户与管理员
一般情况下,我们把数据库的用户分为四类
- 完全无经验用户:他们和事先写好的应用程序交互,根据提示按照规则填写表格,在通过检验后将数据传回数据库存储。当然他们也可以在规则允许的范围内按照提示使用应用程序从数据库获取数据
- 应用程序开发人员:负责编写计算机应用程序的开发人员,在各种开发工具的帮助下他们设计访问数据库的规则来开发应用程序
- 熟练的用户:使用数据库查询语言和数据分析软件访问数据库,他们访问数据库的目的不是开发应用程序而是单纯的获取数据并分析
- 数据库管理员:创建数据库,管理数据库的访问权限,日常维护数据库
关系型数据库简介
关系型数据库的机构
关系数据库由表组成(table)的集合组成,每个表都有唯一的名字。表中的一行代表了一组值之间的联系,一般是从一个特定的ID(不重复的)关联其他信息。 一个表就是这种联系的集合。表的每个列代表各种属性,也就是同类型信息的集合。
在关系模型中,一般用关系(relation)代指一个表,元组(tuble)代指表中的一行,属性(attribute)代指表中的列。关系实例(relation instance)则表示其中特定的一行。
关系是元组的集合,其顺序对于数据库本身是不重要的,我们习惯采用第一个属性的顺序来排列这些元组,在需要使用其他顺序的时候另行查看。
对于关系的每个属性,都存在一个取值的集合,也就是域(domain)。在设计数据库的时候要考虑到这一点。我们一般要求域是原子的,也就是不可再分的,这样可以让我们只需要比对取值情况来判断一些问题,避免设计其他规则来提取域的数据。
一般的数据库我们允许存在空值(null),用来表示值目前未知或者不存在,原则上对于每个表中最重要的那个用作ID的列,我们不会让他是空的
Key
我们前面说了,为了区分关系中不同的元组,我们需要属性来实现这个区分,这个属性(集合)称为码(key)。没有任何一个关系有两个元组在key上取值都相同。
超码(superkey)是一些属性的集合,他们可以让我们在一个关系中唯一的确定一个元组。我们一般只对那些任意真子集都不是超码的超码感兴趣,这称为候选码。候选码在很多的数据库中是不唯一的。
由于候选码可能不唯一,因此我们用主码(primary key)代指被数据库的设计者选中的候选码。主码的选择一定要慎重,选择那些基本不变的属性。我们习惯性的将主码放在所有属性的最前方。
一个关系的可能在其主码以外的属性中含有另一个关系模式的主码,我们一般将其称为外码(foreign key)。外码的存在可以帮助我们将一个数据库的多个表快速联系起来。
关系查询语言与关系运算
查询语言表示那些用户从数据库中请求获取信息的语言,一般可以分为过程化的和非过程化的
- 过程化语言需要我们给出查询的具体过程
- 非过程化的语言需要我们给出想要的具体信息 实际使用的查询语言会同时包括过程化和非过程化的内容,具体可以参考SQL 基础
所有的过程化关系查询语言都提供一组运算,这些运算可以施加在单个关系上,也可以施加在一对关系上,这些运算有一个共同的性质 运算的结果总是单个关系 因此人们可以组合这些常见的运算,得到想要的数据。
最常用的关系运算是从单个关系中选择出满足一些特定谓词的关系,比如 salary > 500 ,他的运算结果是一个新的关系,是原始的关系的一个子集。
另一个常用的运算是选择出特定的列,返回的结果是一个新的只包含特定的属性的新关系。
我们也就联结运算帮助我们从多个表中比较一些列实现多表的整合。
由于本质上关系就是元组的集合,因此那些适用于集合的并 交 补运算也适用于关系,这是一种纵向的,调整行而不是列的合并方法。
我们这里介绍到的关系都可以在 SQL 基础 里面见到真实的操作实践。
事务
事务(transaction)由查询和(或)更新语句组成,我们所完成的,称得上是一个整体的SQL代码都可以称为一个事务。
当一个SQL语句被执行的时候,就隐形的开始一个事务,当下列SQL语句被执行的时候,这个事务才算结束
- Commit work:提交目前的事务,将该事务所进行的更新在数据库中持久保存,在Commit后,一个新的事务自动开始
- Rollback work:回滚当前事务,撤销这个事务中对数据库进行的更新,恢复到这个事务第一句语句之前的状态
关键词 work 均可以省略
事实上,如果我们所书写的一些SQL代码都会立刻反馈到服务器上对所有用户造成影响,那我们就无法测试代码了。事务的存在就是为了能让我们在确认代码正确无误后再对数据库进行修改。
事务的存在是为了保证那些更新数据库内容的语句存在原子性,从而避免更新出错
至于更加完善的事务设计一般是数据库管理人与啊才需要关注的,作为数据库的使用者,我们这里后面只需要根据他们预设的规则写出并且提交SQL语句。
数据库设计
设计过程概览
构建一个数据库是一个复杂的内容,包括设计数据库的模式,设计访问的限制,设计更新数据的程序以及设计数据库的安全模式。我们这里着重于数据库模式的设计,至于其他相关内容仅简要概括,毕竟其泛用性较低。
数据库的设计必须和应用数据库的用户交流来明确了解其需求,完整的刻画未来数据库用户的数据需求,再根据需求选择合适的数据模式,将需求转化为数据库的概念模式,在这个步骤中,最常用的手段是 ER 模型。
数据库设计的一个主要部分是决定如何在设计中表示各种类型的事务,也就是所谓的实体(entity) 他需要包括所有可以明确识别的个体,比如大学数据库中的教师 学生 院系 课程等等。这些各种各样的实体以多种方式相互关联。
在设计实体和他们的联系的时候,要避免两个重要的缺陷
- 冗余:不好的设计会重复信息,冗余的信息最明显的问题出在数据的更新上,当对一条信息进行了更新但是没有对其拷贝更新的时候,数据库将拥有自相矛盾的内容
- 不完整:不好的设计会让某些地方无法被建模,如果只存储开课而不存储课程,那开课会重复存储课程的全部信息,没有被开设的课程也将无法存储。
在实体-联系模型中,我们力求解决前面所提到的问题,但是当数据库变得庞大的时候,依靠人来判断是否出现问题也不足够了,因此我们会介绍一些算法
实体-联系模型
实体联系模型(E-R 模型)是设计数据库的最常用手段,可以把现实世界的含义与交互映射到概念模式上,大部分数据库设计工具都利用了ER模型的概念。他采用了三个基本概念, 实体集 联系集 属性。ER模型还与ER图关联,我们在后面单独介绍
实体集
实体指现实世界中的一个对象与事务,比如一个学生,一个部分等。一个实体拥有一些性质,其中一些性质的值可以唯一的标示一个群体。
实体集是相同类型(具有相同的性质)的一个实体的集合,比如全体学生是一个实体集,全体教师也是。
实体集不需要互不相交,一个实体可以同时属于多个实体集,但是为了避免冗余,他们最好包含不同的属性。
实体通过一组属性来表示,他是实体集每个成员所具有的描述性的性质。每个属性都有一个值。
联系集
联系指的是多个实体之间的相互关联,比如我们可以关联教师实体与学生实体,他们之间的联系是导师关系。联系可以是两个实体集之间的实体相互联系,也可以是同一个实体集中的实体进行联系
联系集是相同类型的联系的集合,将某一特定类型的联系单独抽象出来构成了集合。实体在联系中的功能是角色,当需要解释联系的含义的时候就需要了解他。
联系也可以具有描述性的属性,比如导师关系就可以用一个开始指导的时间进行描述。
联系集中的联系实例用其参与的实体进行唯一的标示,因此我们联系集的描述性的属性是补充信息所用,而不是联系集的唯一标示
联系集可以是多元的,也就是联系三个及以上实体,但是二元的是最主要的
在设计联系集中的属性的名字的时候,要注意避免出现重复,因为其属性多是从其他实体集中获取的,很可以出现本身是重复的情况,比如最常用的ID
属性
每个属性都有一个取值集合,称为属性的域(domain)。每个实体集都可以用一组(属性,数据值)对来进行标示,每个属性都对应了一个这样的对。
ER模型的属性可以按照下面的属性类型来进行划分
- 简单属性与复合属性:简单属性意味着他不可以被划分为更小的部分,而复合属性可以,目前我们主要使用的属性都是简单属性,但是我们也可以在一些模式中设计复合属性,将一些相关的属性聚集起来,例如 address 复合属性,含有 street city state code 四个简单属性作为其子属性。
- 单值属性与多值属性:这意味着一个属性可以对应一组值而不是一个值,目前我们使用的属性以单值为主
- 派生属性:这类属性的值可以从其他相关属性或者实体派生(计算)得到,例如工资表中的sum
约束
ER图可以定义一些数据库中的数据必须要满足的约束,这里进行介绍
映射基数
映射基数(mapping cardinality)表示一个实体通过一个联系集能关联的实体的个数。
在二元联系集合 联系实体集 的时候,映射基数有下面四种情况
- 一对一
- 一对多
- 多对一
- 多对多
特地联系集的映射基数依赖于该联系集所建模的现实世界的情况
参与约束
如果中的每个实体都参与到联系集 的至少一个联系中,则称E在R中是全部的,反之则称为部分的。我们可以对联系的全部或者部分进行约束。
Key
实体集中Key的机制我们已经在 前文关系模型的 Key 部分中介绍过了,我们可以凭借其中的主码来唯一的标识出一个实体,但是联系集中的联系该如何标示则成了一个问题。
我们能明确的清楚: 联系集的主码依赖于其关联的实体集的码(属性的集合)
如果联系集中没有自己单独的属性,那么使用每一个其关联的实体的主码就可以唯一标示一个联系。
如果联系集有自己单独的属性,那么需要用这些主码以及他们属性的并来确定一个联系。
从实体集中删除冗余属性
当我们是使用ER模型设计数据库的时候,我们通常从其包含的实体集开始,具体包含什么属性取决于设计者与使用者的交流。
当选择好实体和他们对应的属性以后,不同实体的联系集就自然的建立起来了,这些联系可能会导致不同实体集中属性冗余,需要删除他们。我们用下面的例子来说明
考查实体集 instructor 和 department
- 实体集 instructor 包含 ID ,name,dept_name,salary 其中 ID 构成主码
- 实体集 department 包含 dept_name,buliding,,budget 其中 dept_name 构成主码
我们用关联二者的联系集 inst_dept 关联每个教师所属于的院系,能看出,属性dept_name在两个实体集中都出现了,并且在department 属于主码,因此应该将其在instructor中删除,当需要访问是经由联系集inst_dept 来访问
将这里的思路拓展到一个含有多个实体集与多个联系集的数据库中,就可以删除冗余的属性。
实体-联系图
一个实体-联系图有下面的主要构件
- 分成两部分的矩形代表实体集,包含实体集的名字,属性,其中主键用下划线标出
- 菱形代表一个联系集
- 没有分割的代表联系集的属性
- 实线和虚线分别连接实体与联系,联系与联系的属性
如果有一对一,多对一等映射基数的问题,我们则使用实线上的箭头来标示,从指向 则意味着此方向只可以一对多。
如果出现复合属性,则应该使用缩进的属性来表示。
原则上,我们最后绘制的ER图应该是一个整体,用一整张图标示出各个实体,联系与属性
关系设计与好的关系设计
我们可以直接从ER图中产生一个关系型数据库的关系模式,我们希望他满足适当的范式(normal form),可以让我们方便的获取信息并且没有冗余。但是直接从ER图中生成的关系模式可能并不足够,我们需要在这里展开进一步的讨论。
我们需要先用例子来说明一下我们在讨论的问题
更大的模式
我们还是用前面的 实体集 instructor 和 department 来讨论,我们是否可以把他们合成一个实体集 inst_dept 他包含 两者的全部属性,这样就可以减少很多查询所需要使用的多数据库连接
不过很遗憾,我们能发现这里出现了数据冗余的问题,每个instructor 都对应了一个budget,而每个department的budget是一样的,这明显会导致不一致的风险。
即时我们解决了冗余的问题,还有一个问题就是建立新的department和一个instructor关联了,因为ID是主键,因此我们无法直接建立一个department 而必须去寻找一个新的教师才能建立他
更小的模式
我们现在从inst_dept 我们如何发现他存储信息重复需要拆分为两个模式呢?
当然我们可以依靠人工的观察,不过这是很不靠谱。因为大型数据库会庞大到人没有精力去探查重复。
因此,我们需要研究后面将会介绍的规范方法,找到正确的分解。而不是错误的分解导致无法有效的表示出原本就有的信息。
也就是我们有两个分解的要点
- 去处原本错误的合并导致的冗余
- 避免新的分解产生信息的丢失
比较常用的用于分解的算法有
- BCNF
- 3NF
原子域与第一范式
ER模型允许实体集与联系集具有某些程度的子结构,比如多值属性与组合属性。不过当我们从ER模型创建表的时候,要消除这种子结构。
- 对于组合属性,让每个子属性本身称为属性
- 对于多值属性,为多值集合中的每一个项创建一条元组
在关系模型中,我们将不具有任何子结构的思想形式化。一个域是原子的,该域的元素被认为是不可分的单元。我们将满足原子域的关系模式称为满足第一范式
值得注意的是,我们在实际的数据库中很可能有非原子的域,比如ID为CS001,其中的CS就标示了计算机系。使用数据库的人都会这么认为,然而只要数据库本身认为其是不可分的,那就满足第一范式
在实际的使用中,使用者认为不满足范式的情况非常普遍,这一般是设计者为了数据库性能或者为了一些查询更容易书写或接近现实情况而进行的妥协。
这也意味着有时候我们无法在数据库系统内将问题解决,需要依赖一些自由度更高的编程语言来实现我们想要的效果。至于如何将其他的语言和数据库连接,我们在研究程序设计的时候再进行讨论。
- Title: Database Systems Concepts: Data Models, Transactions, and Query Processing
- Author: Hyacehila
- Created at : 2024-12-23 11:42:58
- Link: https://hyacehila.github.io//blog/2024/12/23/database-systems-concepts/
- License: This work is licensed under CC BY-NC-SA 4.0.
