BeginnersBook-数据库教程-一-
BeginnersBook 数据库教程(一)
DBMS 中的数据模型
数据模型是数据库的逻辑结构。它描述了数据库的设计,以反映实体,属性,数据之间的关系,约束等。
数据模型的类型
DBMS 中有几种类型的数据模型。我们将在单独的文章中详细介绍它们(下面已经提供了与这些单独教程的链接)。在本指南中,我们将看到模型类型的基本概述。
基于对象的逻辑模型 - 描述概念和视图层的数据。
- E-R 模型
- 面向对象模型
基于记录的逻辑模型 - 与基于对象的模型类似,它们也描述概念和视图层的数据。这些模型使用记录,字段和属性指定数据库的逻辑结构。
物理数据模型 - 这些模型描述最低抽象级别的数据。
实体关系图 - DBMS 中的 ER 图
实体关系模型(ER 模型)借助于图来描述数据库的结构,其被称为实体关系图(ER 图)。 ER 模型是数据库的设计或蓝图,以后可以实现为数据库。 E-R 模型的主要组成部分是:实体集和关系集。
什么是实体关系图(ER 图)?
ER 图显示了实体集之间的关系。实体集是一组相似的实体,这些实体可以具有属性。就 DBMS 而言,实体是数据库中表的表或属性,因此通过显示表及其属性之间的关系,ER 图显示了数据库的完整逻辑结构。让我们看一个简单的 ER 图来理解这个概念。
一个简单的 ER 图:
在下图中,我们有两个实体Student
和College
及其关系。Student
与College
之间的关系是多对一的,因为大学可以有很多学生,但学生不能同时在多所大学学习。Student
实体具有诸如Stu_Id
,Stu_Name
和 Stu_Addr
等属性。College
实体具有Col_ID
和COL_NAME
等属性。
以下是 E-R 图中的几何形状及其含义。我们将在本指南的下一部分(ER 图的组成部分)中详细讨论这些术语,所以现在不要过多担心这些术语,只需浏览一次。
矩形 :表示实体集。
椭圆:属性
菱形:关系集
直线:它们将属性链接到实体集,将实体集链接到关系集
双椭圆:多值属性
虚线椭圆:派生属性
双矩形:弱实体集
双线:实体在关系集中的完全参与
ER 图的组成部分
如上图所示,ER 图有三个主要组成部分:
- 实体
- 属性
- 关系
1. 实体
实体是数据的对象或组件。实体在 ER 图中表示为矩形。
例如:在下面的 ER 图中,我们有两个实体学生和学院,这两个实体有多对一的关系,因为许多学生在一所大学学习。我们稍后会阅读更多关于关系的内容,现在关注实体。
弱实体:
无法通过其自身属性唯一标识并依赖于与其他实体的关系的实体称为弱实体。弱实体由双矩形表示。例如,如果不知道该帐户所属的银行,就无法唯一识别银行帐户,因此银行帐户是一个弱实体。
2. 属性
属性描述实体的属性。 ER 图中的属性表示为椭圆。有四种类型的属性:
- 关键属性
- 复合属性
- 多值属性
- 派生属性
1. 关键属性:
关键属性可以唯一地标识实体集中的实体。例如,学生编号可以唯一地标识来自一组学生的学生。关键属性由椭圆表示,与其他属性相同,但关键属性的文本加下划线。
2. 复合属性:
属于其他属性组合的属性称为复合属性。例如,在学生实体中,学生地址是复合属性,因为地址由其他属性组成,例如密码,状态,国家。
3. 多值属性:
可以包含多个值的属性称为多值属性。它在 ER 图中用双椭圆表示。例如 - 一个人可以拥有多个电话号码,因此电话号码属性是多值的。
4. 派生属性:
派生属性的值是动态的,并且是从另一个属性派生的。它由 ER 图中的虚线椭圆表示。例如 - Person age
是一个派生属性,因为它随时间变化,可以从另一个属性(出生日期)派生。
具有多值和派生属性的 E-R 图:
3. 关系
ER 图中的菱形表示关系,表示实体之间的关系。有四种类型的关系:
- 一对一
- 一对多
- 多对一
- 多对多
1. 一对一的关系
当实体的单个实例与另一个实体的单个实例相关联时,它被称为一对一关系。例如,一个人只有一本护照,一本护照只能被一个人获得。
2. 一对多的关系
当一个实体的单个实例与另一个实体的多个实例相关联时,它被称为一对多关系。例如 - 客户可以下许多订单,但许多客户无法下一个订单。
3. 多对一的关系
当实体的多个实例与另一个实体的单个实例相关联时,它被称为多对一关系。例如,许多学生可以在一所大学学习,但学生不能同时在许多大学学习。
4. 多对多关系
当一个实体的多个实例与另一个实体的多个实例相关联时,它被称为多对多关系。例如,可以将学生分配给许多项目,并将项目分配给许多学生。
实体集的完全参与
实体集的完全参与表示实体集中的每个实体必须在关系集中具有至少一个关系。例如:在下图中,每个学院必须至少有一个相关的学生。
DBMS 泛化
泛化是一个过程,其中多个实体的共同属性构成一个新实体。这个新形成的实体称为泛化实体。
泛化示例
让我们说我们有两个实体学生和老师。
实体学生的属性是:姓名,地址和年级。
实体教师的属性是:姓名,地址和薪水。
泛化前的 ER 图如下所示:
这两个实体有两个共同的属性:Name
和Address
,我们可以使用这些公共属性创建一个泛化实体。让我们看一下泛化后的 ER 模型。
泛化后的 ER 图:
我们创建了一个新的泛化实体Person
,这个实体具有两个实体的共同属性。正如你在下面的 ER 图中看到的那样,在泛化过程之后,实体Student
和Teacher
分别只有Grade
和Salary
的专用属性,它们的公共属性(Name
和Address
)现在与新实体Person
关联,它与两个实体(学生和教师)关联。
注:
- 泛化使用自下而上的方法,其中两个或多个较低级别的实体组合在一起形成更高级别的新实体。
- 新的泛化实体可以进一步与较低级别的实体组合在一起,以创建更高级别的泛化实体。
DBMS 特化
特化是将实体划分为子实体的过程。您可以将其视为泛化的逆过程,其中两个实体组合在一起形成一个新的更高级别的实体。特化是一个自上而下的过程。
特化背后的想法是找到没有区分属性的实体子集。例如 - 考虑一个实体员工,可以进一步分类为子实体技术员,工程师和会计,因为这些子实体没有区分属性。
特化示例
在上图中,我们可以看到我们有一个更高级别的实体“员工”,我们将其划分为子实体“技术员”,“工程师”和“会计”。所有这些只是公司的一名员工,但他们的角色完全不同,他们几乎没有不同的属性。仅举例来说,我已经证明技术人员处理服务请求,工程师处理项目,会计处理信贷和借记明细。所有这三种员工类型都没有共同属性,例如我们留下的名称和薪水,与父实体“员工”相关联,如上图所示。
DBMS 聚合
聚合是单独的单个实体无法在关系中有意义,因此两个实体的关系充当一个实体的过程。我知道这听起来令人困惑,但不要担心我们将采取的例子,将清除所有的疑虑。
聚合示例
在现实世界中,我们知道经理不仅管理在他们下工作的员工,而且还必须管理项目。在这种情况下,如果实体“经理”与“员工”或“项目”实体单独建立“管理”关系,那么它将没有任何意义,因为他必须管理两者。在这些情况下,两个实体的关系充当一个实体。在我们的例子中,“员工”和“项目”之间的关系“从事”充当一个实体,与实体“经理”具有“管理”关系。
DBMS 中的关系模型
原文: https://beginnersbook.com/2015/04/relational-model-in-dbms/
在关系模型中,数据和关系由相互关联的表的集合表示。每个表都是一组列和行,其中列表示实体的属性,行表示记录。
样本关系模型:具有 3 列和 4 个记录的学生表。
表:学生
Stu_Id |
Stu_Name |
Stu_Age |
---|---|---|
111 | Ashish | 23 |
123 | Saurav | 22 |
169 | Lester | 24 |
234 | Lou | 26 |
表:课程
Stu_Id |
COURSE_ID |
COURSE_NAME |
---|---|---|
111 | C01 | Science |
111 | C02 | DBMS |
169 | C22 | Java |
169 | C39 | Computer Networks |
这里Stu_Id
,Stu_Name
和Stu_Age
是表Student
的属性,Stu_Id
,Course_Id
和Course_Name
是Course
表的属性。具有值的行是记录(通常称为元组)。
RDBMS 概念
RDBMS 代表关系数据库管理系统。关系模型可以表示为行和列的表。关系数据库有以下主要组成部分:
- 表
- 记录或元组
- 字段或列名称或属性
- 域
- 实例
- 模式
- 键
1. 表
表是以行和列表示的数据的集合。每个表在数据库中都有一个名称。例如,下表STUDENT
将学生的信息存储在数据库中。
表:学生
Student_Id |
Student_Name |
Student_Addr |
Student_Age |
---|---|---|---|
101 | Chaitanya | Dayal Bagh, Agra | 27 |
102 | Ajeet | Delhi | 26 |
103 | Rahul | Gurgaon | 24 |
104 | Shubham | Chennai | 25 |
2. 记录或元组
表的每一行称为记录。它也被称为元组。例如,以下行是我们从上表中获取的记录。
102 | Ajeet | Delhi | 26 |
3. 字段或列名称或属性
上表STUDENT
有四个字段(或属性):Student_Id
,Student_Name
,Student_Addr
& Student_Age
。
4. 域
域是表中属性的一组允许值。例如,月份的域可以接受 1 月,2 月,... 12 月作为值,日期的域可以接受所有可能的有效日期等。我们在创建表时指定属性的域。
属性不能接受域外的值。例如,在上表STUDENT
中,Student_Id
字段具有整数域,因此该字段不能接受非整数的值,例如,Student_Id
不能具有"First"
,10.11
等值。
5. 实例和模式
我已在单独的指南中介绍了实例和模式,您可以参考指南。
6. 键
这是我们的下一个主题,我在单独的教程中详细介绍了键。您可以在此处参考:键。
DBMS 中的分层模型
原文: https://beginnersbook.com/2015/04/hierarchical-model-in-dbms/
在分层模型中,数据被组织成树状结构,每个记录具有一个父记录和许多子记录。该模型的主要缺点是,节点之间只能有一对多的关系。
注意:现在很少使用分层模型。
样本层次模型图:
让我们说我们有一些学生和一些课程,一个课程只能分配给一个学生,但是学生可以选修任意数量的课程,这样这种关系就变成了一对多。
表示为关系表的分层数据示例:上述分层模型可以表示为关系表,如下所示:
Student
表:
Stu_Id |
Stu_Name |
Stu_Age |
---|---|---|
123 | Steve | 29 |
367 | Chaitanya | 27 |
234 | Ajeet | 28 |
Course
表:
COURSE_ID |
COURSE_NAME |
Stu_Id |
---|---|---|
C01 | COBOL | 123 |
C21 | Java | 367 |
C22 | Perl | 367 |
C33 | JQuery | 234 |
DBMS 语言
数据库语言用于读取,更新和存储数据库中的数据。有几种这样的语言可用于此目的;其中之一是 SQL(结构化查询语言)。
DBMS 语言的类型:
数据定义语言(DDL)
DDL 用于指定数据库模式。它用于在数据库中创建表,模式,索引,约束等。让我们看看我们可以使用 DDL 在数据库上执行的操作:
- 创建数据库实例 -
CREATE
- 改变数据库的结构 -
ALTER
- 删除数据库实例 -
DROP
- 删除数据库实例中的表 -
TRUNCATE
- 重命名数据库实例 -
RENAME
- 从数据库中删除对象,例如表 -
DROP
- 注释 - 注释
所有这些命令都定义或更新数据库模式,这就是它们归入数据定义语言的原因。
数据处理语言(DML)
DML 用于访问和操作数据库中的数据。数据库的以下操作属于 DML:
数据控制语言(DCL)
DCL 用于授予和撤销数据库上的用户访问权限:
- 授予用户访问权限 -
GRANT
- 撤消用户的访问权限 -
REVOKE
在实际数据定义语言中,数据处理语言和数据控制语言不是单独的语言,而是它们是单个数据库语言(如 SQL)的一部分。
事务控制语言(TCL)
我们使用 DML 命令进行的数据库更改是使用 TCL 执行或回滚的。
- 提交 DML 命令在数据库中所做的更改 -
COMMIT
- 要回滚对数据库所做的更改 -
ROLLBACK
DBMS 关系代数
原文: https://beginnersbook.com/2019/02/dbms-relational-algebra/
在本教程中,我们将讨论关系代数。在前面的教程中,我们简要讨论了关系代数和微积分的基础知识,其中我们了解了使用这些理论数学系统的必要性。
什么是 DBMS 中的关系代数?
关系代数是一种过程查询语言,适用于关系模型。查询语言的目的是从数据库中检索数据或对数据执行各种操作,如插入,更新,删除。当我说关系代数是一种过程查询语言时,它意味着它告诉我们要检索哪些数据以及如何检索它们。
另一方面,关系演算是一种非过程式查询语言,这意味着它会告诉要检索哪些数据但不会告诉如何检索它。我们将在单独的教程中讨论关系演算。
关系代数中的运算类型
我们将这些操作分为两类:
- 基本操作
- 派生操作
基本/基本操作:
- 选择(
σ
) - 投影(
Π
) - 并集(
∪
) - 差集(
-
) - 笛卡尔积(
X
) - 重命名(
ρ
)
衍生操作:
- 自然连接(
⋈
) - 左,右,全外连接(
⟕
,⟖
,⟗
) - 交集(
∩
) - 除法(
÷
)
让我们在示例的帮助下逐一讨论这些操作。
选择运算符(σ
)
选择运算符由 sigma(σ
)表示,它用于查找满足给定条件的关系(或表)中的元组(或行)。
如果您了解一点 SQL,那么您可以将其视为 SQL 中的where
子句,它用于相同的目的。
选择运算符语法(σ
)
σ Condition/Predicate(Relation/Table name)
选择运算符(σ
)示例
Table: CUSTOMER
---------------
Customer_Id Customer_Name Customer_City
----------- ------------- -------------
C10100 Steve Agra
C10111 Raghu Agra
C10115 Chaitanya Noida
C10117 Ajeet Delhi
C10118 Carl Delhi
查询:
σ Customer_City="Agra" (CUSTOMER)
输出:
Customer_Id Customer_Name Customer_City
----------- ------------- -------------
C10100 Steve Agra
C10111 Raghu Agra
投影运算符(Π
)
投影运算符由Π
符号表示,用于从表(或关系)中选择所需的列(或属性)。
关系代数中的投影运算符类似于 SQL 中的Select
语句。
投影运算符语法(Π
)
∏ column_name1, column_name2, ...., column_nameN(table_name)
投影运算符(Π
)示例
在这个例子中,我们有一个包含三列的表CUSTOMER
,我们只想获取表的两列,我们可以在投影运算符Π
的帮助下完成。
Table: CUSTOMER
Customer_Id Customer_Name Customer_City
----------- ------------- -------------
C10100 Steve Agra
C10111 Raghu Agra
C10115 Chaitanya Noida
C10117 Ajeet Delhi
C10118 Carl Delhi
查询:
∏ Customer_Name, Customer_City (CUSTOMER)
输出:
Customer_Name Customer_City
------------- -------------
Steve Agra
Raghu Agra
Chaitanya Noida
Ajeet Delhi
Carl Delhi
并集运算符(∪
)
并集运算符用∪
符号表示,用于从两个表(关系)中选择所有行(元组)。
让我们再讨论一下并集运算符。假设我们有两个关系R1
和R2
都有相同的列,我们想从这些关系中选择所有元组(行),然后我们可以在这些关系上应用并集运算符。
注意:两个表中存在的行(元组)只在并集中出现一次。简而言之,您可以说并集操作后没有重复项。
并集运算符的语法(∪
)
table_name1 ∪ table_name2
并集运算符(∪
)示例
表 1:Course
Course_Id Student_Name Student_Id
--------- ------------ ----------
C101 Aditya S901
C104 Aditya S901
C106 Steve S911
C109 Paul S921
C115 Lucy S931
表 2:Student
Student_Id Student_Name Student_Age
------------ ---------- -----------
S901 Aditya 19
S911 Steve 18
S921 Paul 19
S931 Lucy 17
S941 Carl 16
S951 Rick 18
查询:
∏ Student_Name (COURSE) ∪ ∏ Student_Name (STUDENT)
输出:
Student_Name
------------
Aditya
Carl
Paul
Lucy
Rick
Steve
注意:正如你所看到的那样,输出中没有重复的名称,即使我们在两个表中都有很少的共同名称,同样在COURSE
表中我们也有重复的名称。
交集运算符(∩
)
交集运算符用∩
符号表示,用于从两个表(关系)中选择公共行(元组)。
假设我们有两个关系R1
和R2
都有相同的列,我们想要选择两个关系中存在的所有元组(行),那么在这种情况下我们可以对这两个关系R1∩R2
应用交集运算。
注意:只有那两个表中存在的那些行才会出现在结果集中。
交集运算符语法(∩
)
table_name1 ∩ table_name2
交集运算符(∩
)示例
让我们采取与上面相同的例子。
表 1:Course
Course_Id Student_Name Student_Id
--------- ------------ ----------
C101 Aditya S901
C104 Aditya S901
C106 Steve S911
C109 Paul S921
C115 Lucy S931
表 2:STUDENT
Student_Id Student_Name Student_Age
------------ ---------- -----------
S901 Aditya 19
S911 Steve 18
S921 Paul 19
S931 Lucy 17
S941 Carl 16
S951 Rick 18
查询:
∏ Student_Name (COURSE) ∩ ∏ Student_Name (STUDENT)
输出:
Student_Name
------------
Aditya
Steve
Paul
Lucy
差集运算符(-
)
差集运算符用-
符号表示。假设我们有两个关系R1
和R2
,我们想要选择所有那些存在于关系R1
中但不存在于关系R2
中的元组(行),这可以使用集合差R1-R2
来完成。
差集运算符语法(-
)
table_name1 - table_name2
差集运算符(-
)示例
让我们看看上面我们看到的课程和学生。
查询:
让我们编写一个查询来选择STUDENT
表中但不存在于COURSE
表中的学生姓名。
∏ Student_Name (STUDENT) - ∏ Student_Name (COURSE)
输出:
Student_Name
------------
Carl
Rick
笛卡尔积(X
)
笛卡尔积用X
符号表示。假设我们有两个关系R1
和R2
,然后这两个关系的笛卡尔积(R1 X R2
)将第一关系R1
的每个元组与第二关系R2
的每个元组组合。我知道这听起来令人困惑,但是一旦我们举一个这样的例子,你就能理解这一点。
笛卡尔积(X
)的语法
R1 X R2
笛卡尔积(X
)示例
表 1:R
Col_A Col_B
----- ------
AA 100
BB 200
CC 300
表 2:S
Col_X Col_Y
----- -----
XX 99
YY 11
ZZ 101
查询:
让我们查找表R
和S
的笛卡尔积。
R X S
输出:
Col_A Col_B Col_X Col_Y
----- ------ ------ ------
AA 100 XX 99
AA 100 YY 11
AA 100 ZZ 101
BB 200 XX 99
BB 200 YY 11
BB 200 ZZ 101
CC 300 XX 99
CC 300 YY 11
CC 300 ZZ 101
注意:输出中的行数始终是每个表中行数的乘积。在我们的示例中,表 1 有 3 行,表 2 有 3 行,因此输出有3×3 = 9
行。
重命名(ρ
)
重命名(ρ
)操作可用于重命名关系的属性。
重命名(ρ
)语法:
ρ(new_relation_name, old_relation_name)
重命名(ρ
)示例
假设我们有一个表Customer
,我们正在获取客户名称,我们将所得关系重命名为CUST_NAMES
。
表:客户
Customer_Id Customer_Name Customer_City
----------- ------------- -------------
C10100 Steve Agra
C10111 Raghu Agra
C10115 Chaitanya Noida
C10117 Ajeet Delhi
C10118 Carl Delhi
查询:
ρ(CUST_NAMES, ∏(Customer_Name)(CUSTOMER))
输出:
CUST_NAMES
----------
Steve
Raghu
Chaitanya
Ajeet
Carl
DBMS 简介
DBMS 代表 D ata b ase M aagement S ystem。我们可以像 DBMS = Database + Management System 那样打破它。数据库是数据的集合,管理系统是一组用于存储和检索这些数据的程序。基于此,我们可以像这样定义 DBMS :DBMS 是一个相互关联的数据和一组程序集合,用于以简单有效的方式存储和访问这些数据。
DBMS 的需求是什么?
数据库系统基本上是为大量数据而开发的。在处理大量数据时,有两件事需要优化:存储数据和检索数据。
存储:根据数据库系统的原理,数据以这样的方式存储,即在存储之前删除冗余数据(重复数据),它可以占用更少的空间。让我们以一个外行的例子来理解这一点:
在银行系统中,假设一个客户有两个账户,一个是储蓄账户,另一个是工资账户。假设银行在一个地方保存储蓄帐户数据(这些地方称为表,我们将在稍后学习),在另一个地方保存工资帐户数据,在这种情况下,如果客户信息,如客户名称,地址等,都存储在两个地方,这只是存储(数据的冗余/重复)的浪费,以更好的方式组织数据,信息应该存储在一个地方,并且两个帐户都应该以某种方式链接到该信息。我们在 DBMS 中这样实现。
快速检索数据:除了以优化和系统的方式存储数据外,在需要时快速检索数据也很重要。数据库系统确保尽快检索数据。
数据库系统的目的
数据库系统的主要目的是管理数据。考虑一所保存学生,教师,课程,书籍等数据的大学。为了管理这些数据,我们需要将这些数据存储在一个地方,其中我们可以添加新数据,删除未使用数据,更新过期数据,检索数据,执行这些操作。在数据方面,我们需要一个数据库管理系统,它允许我们以这样的方式存储数据,以便可以有效地对数据执行所有这些操作。
数据库系统比传统文件处理系统要好得多,我们我们在单独文章中讨论它:DBMS 与文件系统。
DBMS 关系演算
原文: https://beginnersbook.com/2019/02/dbms-relational-calculus/
在上一个教程中,我们讨论了关系代数 ,这是一种过程查询语言。在本教程中,我们将讨论关系演算,它是一种非过程查询语言。
什么是关系演算?
关系演算是一种非过程查询语言,它告诉系统要检索哪些数据但不告诉如何检索它。
关系演算的类型
1. 元组关系演算(TRC)
元组关系演算用于选择满足给定条件的元组。
表:Student
First_Name Last_Name Age
---------- --------- ----
Ajeet Singh 30
Chaitanya Singh 31
Rajeev Bhatia 27
Carl Pratap 28
让我们编写查询的关系演算。
查询来显示年龄大于 30 岁的学生的姓氏。
{ t.Last_Name | Student(t) AND t.age > 30 }
在上面的查询中,您可以看到由|
符号分隔的两个部分。第二部分是我们定义条件的地方,在第一部分中我们为所选元组指定了要显示的字段。
上述查询的结果将是:
Last_Name
---------
Singh
查询来显示姓氏为"Singh"
的学生的所有详细信息。
{ t | Student(t) AND t.Last_Name = 'Singh' }
输出:
First_Name Last_Name Age
---------- --------- ----
Ajeet Singh 30
Chaitanya Singh 31
2. 域关系演算(DRC)
在域关系演算中,记录基于域进行过滤。
我们再次采用相同的表来了解 DRC 的工作原理。
表:Student
First_Name Last_Name Age
---------- --------- ----
Ajeet Singh 30
Chaitanya Singh 31
Rajeev Bhatia 27
Carl Pratap 28
查询来查找年龄大于 27 岁的学生的名字和年龄
{< First_Name, Age > | ∈ Student ∧ Age > 27}
注:
用于逻辑运算符的符号为:∧
表示 AND,∨
表示 OR,┓
表示 NOT。
输出:
First_Name Age
---------- ----
Ajeet 30
Chaitanya 31
Carl 28
DBMS 中的键
键在关系数据库中起着重要作用;它用于从表中标识唯一行。它还建立了表之间的关系。
DBMS 中的键类型
注意:伙计们我一直在评论这里没有关键的例子。如果您单击下面提供的超链接,您将看到每个键的完整单独教程和示例。
主键 - 主键是表中的一列或一组列,用于唯一标识该表中的元组(行)。
超键 - 超键是一组多个列(属性)的集合,用于唯一标识表中的行。
候选键 - 没有冗余属性的超键称为候选键
替代键 - 在所有候选键中,只有一个被选为主键,其余键称为替代键或辅助键。
复合键 - 由多个属性组成的键,用于唯一标识表中的行(也称为记录和元组)称为复合键。
外键 - 外键是表的列,指向另一个表的主键。它们充当表之间的交叉引用。
DBMS 中的主键
定义:主键是表中唯一标识该表中元组(行)的一组最小属性(列)。
DBMS 中的主键示例
让我们举一个例子来理解主键的概念。在下表中,有三个属性:Stu_ID
,Stu_Name
和Stu_Age
。在这三个属性中,一个属性或一组多个属性可以是主键。
单个属性Stu_Name
不能是主键,因为多个学生可以拥有相同的名称。
单个属性Stu_Age
不能成为主键,因为不止一个学生可以拥有相同的年龄。
单个属性Stu_Id
是主键,因为每个学生都有一个唯一的 ID,可以识别表中的学生记录。
注意:在某些情况下,单个属性不能唯一地标识表中的记录,在这种情况下,我们尝试查找可以唯一标识表中的行的一组属性。在这个例子之后我们将看到它的例子。
表名:Student
Stu_Id |
Stu_Name |
Stu_Age |
---|---|---|
101 | Steve | 23 |
102 | John | 24 |
103 | Robert | 28 |
104 | Steve | 29 |
105 | Carl | 29 |
有关主键的注意事项
- 我们通常用下划线表示属性名称(列名)。
- 对于表的每一行,主键的值应该是唯一的。生成键的列不能包含重复值。
- 标记为主键的属性不允许具有空值。
- 主键不一定是单个属性(列)。它可以是一组多个属性(列)。例如
{Stu_Id, Stu_Name}
可以共同识别上表中的元组,但是我们不选择它作为主键,因为单独Stu_Id
就足以唯一地标识表中的行而我们总是去最小的集合。话虽如此,只有当没有可以唯一标识表中的元组的单个列时,我们才应该选择多个列作为主键。
主键的另一个示例 - 多个属性
考虑这个表ORDER
,该表保存了客户购买的每日记录。该表有三个属性:Customer_ID
,Product_ID
和Order_Quantity
。
Customer_ID
单独不能成为主键,因为单个客户可以下多个订单,因此多于一行拥有相同的Customer_ID
值。正如我们在以下示例中看到的那样,客户 ID 1011 已经为产品(如果是 9023 和 9111)下了两个订单。
单独Product_ID
不能成为主键,因为不止一个客户可以为同一产品下订单,因此多个行具有相同的产品 ID。在下表中,客户 ID 1011 和 1122 为同一产品(产品编号 9023)下订单。
单独使用Order_Quantity
不能成为主键,因为不止一个客户可以让订单具有相同的数量。
由于没有一个属性能够成为主键,因此我们尝试创建一组属性作为主键。
{Customer_ID, Product_ID}
一起可以在表中唯一地标识行,因此该集合是该表的主键。
表名:ORDER
Customer_ID |
Product_ID |
Order_Quantity |
---|---|---|
1011 | 9023 | 10 |
1122 | 9023 | 15 |
1099 | 9031 | 20 |
1177 | 9031 | 18 |
1011 | 9111 | 50 |
注意:在为主键选择一组属性时,我们总是选择具有最小属性数的最小集合。例如,如果有两个集合可以标识表中的行,则应选择具有最小属性数的集合作为主键。
如何在 RDBMS 中定义主键?
在上面的示例中,我们已经有了一个包含数据的表,我们试图了解主键的用途和含义,但是您应该知道通常我们在创建表时定义主键。我们也可以稍后定义主键,但在现实场景中很少发生。
假设我们要创建上面讨论过的表,其中客户 ID 和产品 ID 设置为主键。我们可以在 SQL 中这样做:
Create table ORDER
(
Customer_ID int not null,
Product_ID int not null,
Order_Quantity int not null,
Primary key (Customer_ID, Product_ID)
)
假设我们在创建表时没有定义主键,那么我们可以在以后定义它:
ALTER TABLE ORDER
ADD CONSTRAINT PK_Order PRIMARY KEY (Customer_ID, Product_ID);
另一种方式:
当我们只有一个属性作为主键时,就像我们在STUDENT
表的第一个例子中看到的那样。我们也可以像这样定义键:
Create table STUDENT
(
Stu_Id int primary key,
Stu_Name varchar(255) not null,
Stu_Age int not null
)
DBMS 中的超键
DBMS 中超键的定义:超键是一组单个或多个属性(列),可以唯一地标识表中的行。通常 DBMS 初学者混淆超键和候选键,因此我们还将在本文中讨论候选键及其与超键的关系。
候选键如何与超键不同?
答案很简单 - 从超键集中选择候选键,我们在选择候选键时唯一要注意的是:它不应该有任何冗余属性。这就是他们被称为最小超键的原因。
让我们举一个例子来理解这一点:
表:Employee
Emp_SSN Emp_Number Emp_Name
--------- ---------- --------
123456789 226 Steve
999999321 227 Ajeet
888997212 228 Chaitanya
777778888 229 Robert
超键:上表有以下超键。以下所有超键集都能够唯一标识employee
表的一行。
- {} Emp_SSN
- {} Emp_Number
候选键:正如我在开头提到的,候选键是一个没有冗余属性的最小超键。从上述集合中选择以下两组超键,因为这些集合中没有冗余属性。
- {} Emp_SSN
- {} Emp_Number
只有这两组是候选键,因为所有其他组都具有冗余属性,这些属性对于唯一标识不是必需的。
超键与候选键
关于超键和候选键之间的混淆,我收到了很多评论。让我给你一个清楚的解释。
-
首先,您必须了解所有候选键都是超键。这是因为候选键是从超键中选择的。
-
我们如何从超键集中选择候选键?我们寻找那些我们无法删除任何字段的键。在上面的示例中,我们没有选择
{Emp_SSN, Emp_Name}
作为候选键,因为{Emp_SSN}
单独可以识别表中的唯一行,而Emp_Name
是冗余的。
主键:
从一组候选键中选择主键。这是由数据库管理员或数据库设计者完成的。我们可以说可以选择{Emp_SSN}
或{Emp_Number}
作为表Employee
的主键。
DBMS 中的候选键
原文: https://beginnersbook.com/2015/04/candidate-key-in-dbms/
DBMS 中候选键的定义:没有冗余属性的超键被称为候选键。从超键集中选择候选键,在选择候选键时我们唯一要注意的是候选键不应具有任何冗余属性。这就是他们被称为最小超键的原因。
候选键示例
让我们举一个表Employee
的例子。该表有三个属性:Emp_Id
,Emp_Number
和EMP_NAME
。在这里 Emp_Id
和Emp_Number
将具有唯一值,并且Emp_Name
可以具有重复值,因为多个员工可以具有相同的名称。
Emp_Id Emp_Number Emp_Name
------ ---------- --------
E01 2264 Steve
E22 2278 Ajeet
E23 2288 Chaitanya
E45 2290 Robert
上表可以有多少个超键?
{Emp_Id}
{Emp_Number}
{Emp_Id, Emp_Number}
{Emp_Id, Emp_Name}
{Emp_Id, Emp_Number, Emp_Name}
{Emp_Number, Emp_Name}
让我们从上面的一组超键中选择候选键。
{Emp_Id}
- 无冗余属性{Emp_Number}
- 无冗余属性{Emp_Id, Emp_Number}
- 有冗余属性。这些属性中的任何一个都可以是最小超键,因为这两个列都具有唯一值。{Emp_Id, Emp_Name}
- 冗余属性Emp_Name
。{Emp_Id, Emp_Number, Emp_Name}
- 有冗余属性。仅Emp_Id
或Emp_Number
就足以唯一地标识Employee
表的一行。{Emp_Number, Emp_Name}
- 冗余属性Emp_Name
。
我们选择的候选键是:
{Emp_Id}
{Emp_Number}
注:从候选键组中选择主键。这意味着我们可以将Emp_Id
或Emp_Number
作为主键。该决定由 DBA(数据库管理员)完成。
DBMS 中的替代键
原文: https://beginnersbook.com/2015/04/alternate-key-in-dbms/
正如我们在候选键指南中看到的那样,一个表可以有多个候选键。在这些候选键中,只有一个键被选为主键,其余键被称为替代键或辅助键。
替代键示例
让我们举一个例子来理解替代键概念。这里我们有一个表Employee
,这个表有三个属性:Emp_Id
,Emp_Number
和EMP_NAME
。
表:Employee
Emp_Id Emp_Number Emp_Name
------ ---------- --------
E01 2264 Steve
E22 2278 Ajeet
E23 2288 Chaitanya
E45 2290 Robert
上表中有两个候选键:
{Emp_Id}
{Emp_Number}
DBA(数据库管理员)可以选择上述任何一个键作为主键。让我们说Emp_Id
被选为主键。
由于我们选择Emp_Id
作为主键,因此剩余键Emp_Number
将被称为替代键或辅助键。
DBMS 中的复合键
原文: https://beginnersbook.com/2015/04/composite-key-in-dbms/
复合键的定义:具有多个属性的键称为复合键。它也被称为复合键。
注意: 超键,主键,候选键等任何键都可以称为复合键,如果它超过一个属性。
复合键示例
让我们考虑一个表Sale
。该表有四列(属性) - cust_Id
,order_Id
,product_code
和 PRODUCT_COUNT
。
表 - Sale
cust_Id order_Id product_code product_count
-------- -------- ------------ -------------
C01 O001 P007 23
C02 O123 P007 19
C02 O123 P230 82
C01 O001 P890 42
这些列中没有一个可以在此表中充当主键。
单独的 cust_Id
列不能成为一个键,因为同一个客户可以下多个订单,因此同一个客户可以有多个记录。
单独的列 order_Id
不能是主键,因为相同的订单可以包含多个产品,因此可以多次出现相同的order_Id
。
列 product_code
不能是主键,因为多个客户可以为同一产品下订单。
单独的 product_count
列不能是主键,因为两个订单可以具有相同的产品数量。
基于此,可以安全地假设键应具有多个属性:
上表中的键:{cust_id, product_code}
这是一个复合键,因为它由多个属性组成。
DBMS 中的外键
定义:外键是表的列,指向另一个表的主键。它们充当表之间的交叉引用。
例如:
在下面的例子中,Course_enrollment
表中的Stu_Id
列是外键,因为它指向Student
表的主键。
Course_enrollment
表:
COURSE_ID |
Stu_Id |
---|---|
C01 | 101 |
C02 | 102 |
C03 | 101 |
C05 | 102 |
C06 | 103 |
C07 | 102 |
Student
表:
Stu_Id |
Stu_Name |
Stu_Age |
---|---|---|
101 | Chaitanya | 22 |
102 | Arya | 26 |
103 | Bran | 25 |
104 | Jon | 21 |
注意:实际上,外键与另一个表的主键标签无关,如果它指向另一个表的唯一列(不一定是主键),那么它将是一个外键。因此,外键的正确定义是:外键是表的列,指向另一个表的候选键。
DBMS 中的约束
约束强制限制可以从表中插入/更新/删除的数据或数据类型。约束的整个目的是在更新/删除/插入表中时保持数据完整性。在本教程中,我们将学习可以在 RDBMS 中创建的几种类型的约束。
约束的类型
- 非空
- 独特
- 默认
- 校验
- 键约束 - 主键,外键
- 域约束
- 映射约束
非空:
NOT NULL
约束确保列不保存NULL
值。当我们在将记录插入表时不为特定列提供值时,默认情况下它采用NULL
值。通过指定NULL
约束,我们可以确定特定列不能具有NULL
值。
例:
CREATE TABLE STUDENT(
ROLL_NO INT NOT NULL,
STU_NAME VARCHAR (35) NOT NULL,
STU_AGE INT NOT NULL,
STU_ADDRESS VARCHAR (235),
PRIMARY KEY (ROLL_NO)
);
在这里阅读更多关于这个约束的信息。
唯一:
UNIQUE
约束强制一列或一组列具有唯一值。如果列具有唯一约束,则意味着特定列不能在表中具有重复值。
CREATE TABLE STUDENT(
ROLL_NO INT NOT NULL,
STU_NAME VARCHAR (35) NOT NULL UNIQUE,
STU_AGE INT NOT NULL,
STU_ADDRESS VARCHAR (35) UNIQUE,
PRIMARY KEY (ROLL_NO)
);
默认:
当将记录插入表中时没有提供任何值时,DEFAULT
约束为列提供默认值。
CREATE TABLE STUDENT(
ROLL_NO INT NOT NULL,
STU_NAME VARCHAR (35) NOT NULL,
STU_AGE INT NOT NULL,
EXAM_FEE INT DEFAULT 10000,
STU_ADDRESS VARCHAR (35) ,
PRIMARY KEY (ROLL_NO)
);
阅读更多:默认约束
检查:
此约束用于指定表的特定列的值范围。在列上设置此约束时,它确保指定的列必须具有落在指定范围内的值。
CREATE TABLE STUDENT(
ROLL_NO INT NOT NULL CHECK(ROLL_NO >1000) ,
STU_NAME VARCHAR (35) NOT NULL,
STU_AGE INT NOT NULL,
EXAM_FEE INT DEFAULT 10000,
STU_ADDRESS VARCHAR (35) ,
PRIMARY KEY (ROLL_NO)
);
在上面的例子中,我们在STUDENT
表的ROLL_NO
列上设置了检查约束。现在,ROLL_NO
字段的值必须大于 1000。
键的约束:
主键:
主键唯一标识表中的每条记录。它必须具有唯一值,并且不能包含空值。在下面的示例中,ROLL_NO
字段被标记为主键,这意味着ROLL_NO
字段不能具有重复值和空值。
CREATE TABLE STUDENT(
ROLL_NO INT NOT NULL,
STU_NAME VARCHAR (35) NOT NULL UNIQUE,
STU_AGE INT NOT NULL,
STU_ADDRESS VARCHAR (35) UNIQUE,
PRIMARY KEY (ROLL_NO)
);
外键:
外键是表的列,指向另一个表的主键。它们充当表之间的交叉引用。
在这里了解更多相关信息。
域约束:
每个表都有一组特定的列,每列基于其数据类型允许相同类型的数据。该列不接受任何其他数据类型的值。
域约束是用户定义的数据类型,我们可以像这样定义它们:
域约束=数据类型+约束(NOT NULL
/ UNIQUE
/ PRIMARY KEY
/ FOREIGN KEY
/ CHECK
/ DEFAULT
)
映射约束:
DBMS 中的域约束
原文: https://beginnersbook.com/2015/04/domain-constraints-in-dbms/
表是 DBMS 是一组包含数据的行和列。表中的列具有唯一的名称,通常在 DBMS 中称为属性。域是表中属性允许的唯一值集。例如,一个月的域可以接受 1 月,2 月...... 12 月作为可能的值,整数域可以接受负数,正数和零的整数。
定义:域约束是用户定义的数据类型,我们可以这样定义它们:
域约束=数据类型+约束(NOT NULL
/ UNIQUE
/ PRIMARY KEY
/ FOREIGN KEY
/ CHECK
/ DEFAULT
)
示例:
例如,我想创建一个表student_info
,其中stu_id
字段的值大于 100,我可以创建一个域和表,如下所示:
create domain id_value int
constraint id_test
check(value > 100);
create table student_info (
stu_id id_value PRIMARY KEY,
stu_name varchar(30),
stu_age int
);
另一个例子:
我想创建一个表bank_account
,其中account_type
字段的值为checks
或save
:
create domain account_type char(12)
constraint acc_type_test
check(value in ("Checking", "Saving"));
create table bank_account (
account_nbr int PRIMARY KEY,
account_holder_name varchar(30),
account_type account_type
);
数据库应用 - DBMS
原文: https://beginnersbook.com/2015/04/database-applications/
我们使用数据库管理系统的应用是:
- 电信:有一个数据库可以跟踪有关呼叫,网络使用,客户详细信息等的信息。如果没有数据库系统,很难保存每毫秒不断更新的大量数据。
- 行业:如果是制造单位,仓库或配送中心,每个人都需要一个数据库来保存来龙去脉记录。例如,配送中心应跟踪供应到中心的产品单元以及每天从配送中心交付的产品;这就是 DBMS 的用武之地。
- 银行系统:用于存储客户信息,跟踪日常信用和借记事务,生成银行对账单等。所有这些工作都是在数据库管理系统的帮助下完成的。
- 销售:存储客户信息,生产信息和发票详细信息。
- 航空公司:为了通过航空公司旅行,我们提前预订,此预订信息以及航班时刻表存储在数据库中。
- 教育部门:学校和大学经常使用数据库系统来存储和检索有关学生详细信息,员工详细信息,课程详情,考试详情,工资单数据,出勤详情,费用详情等的数据。需要以有效的方式存储和检索的大量相互关联的数据。
- 网上购物:您必须了解亚马逊,Flipkart 等在线购物网站。这些网站存储产品信息,您的地址和偏好,信用详情,并根据您的相关产品列表提供给您查询。所有这些都涉及数据库管理系统。
我已经提到了很少的应用,如果我们开始提到所有的 DBMS 应用,这个列表永远不会结束。
DBMS 中的映射约束
原文: https://beginnersbook.com/2015/04/mapping-constraints-in-dbms/
映射约束可以用映射基数来解释:
映射基数:
一对一:实体集 A 的一个实体可以与实体集 B 中的至多一个实体相关联,实体集 B 中的一个实体可以与实体集 A 中的至多一个实体相关联。
一对多:实体集 A 的一个实体可以与实体集 B 的任意数量的实体相关联,并且实体集 B 中的一个实体可以与实体集中 A 的至多一个实体相关联。
多对一:实体集 A 的一个实体可以与实体集 B 中的至多一个实体相关联,并且实体集 B 中的一个实体可以与实体集 A 的任意数量的实体相关联。
多对多:实体集 A 的一个实体可以与实体集 B 的任意数量的实体相关联,并且实体集 B 中的一个实体可以与实体集 A 的任意数量的实体相关联。
在数据库中创建表时,我们可以使用这些约束。
示例:
CREATE TABLE Customer (
customer_id int PRIMARY KEY NOT NULL,
first_name varchar(20),
last_name varchar(20)
);
CREATE TABLE Order (
order_id int PRIMARY KEY NOT NULL,
customer_id int,
order_details varchar(50),
constraint fk_Customers foreign key (customer_id)
references dbo.Customer
);
假设客户下订单不止一次,上述关系代表一对多关系。同样,我们可以根据需求实现其他映射约束。
DBMS 中的基数
在 DBMS 中,您可以在两个不同的地方听到基数术语,它也有两种不同的含义。
在数据模型的背景下:
就数据模型而言,基数是指两个表之间的关系。如实体关系指南中所见,关系可以是四种类型:
一对一 - 第一个表的单行与第二个表的单行相关联。例如,人与护照表之间的关系是一对一的,因为一个人只能拥有一本护照,而护照只能分配给一个人。
一对多 - 第一个表的单行与第二个表的多行相关联。例如,客户和订单表之间的关系是一对多,因为客户可以下多个订单,但单个订单只能属于一个客户。
多对一 - 第一个表的多行与第二个表的单行相关联。例如,学生和大学表之间的关系是多对一的,因为大学可以有很多学生,但学生一次只能在一所大学学习。
多对多 - 第一个表的多行与第二个表的多行相关联。例如,学生和课程表之间的关系是多对多的,因为学生可以一次学习很多课程,并且可以将课程分配给许多学生。
在查询优化的上下文中:
在查询方面,基数是指表中列的唯一性。具有所有唯一值的列将具有高基数,并且具有所有重复值的列将具有低基数。这些基数得分有助于查询优化。
DBMS 中的函数依赖
原文: https://beginnersbook.com/2015/04/functional-dependency-in-dbms/
当表的属性唯一地标识同一表的另一个属性时,表的属性被认为是彼此依赖的。
例如:假设我们有一个包含属性的学生表:Stu_Id
,Stu_Name
,Stu_Age
。这里Stu_Id
属性唯一地标识学生表的Stu_Name
属性,因为如果我们知道学生 ID,我们可以告诉与之相关的学生姓名。这被称为函数依赖,可以写成Stu_Id -> Stu_Name
,或者我们可以说Stu_Name
在函数上依赖于Stu_Id
。
正式:
如果表的列A
唯一地标识同一表的列B
,那么它可以表示为A -> B
(属性B
在函数上依赖于属性A
)。
函数依赖的类型
DBMS 中的平凡函数依赖
原文: https://beginnersbook.com/2015/04/trivial-functional-dependency-in-dbms/
如果属性集包含某属性,则该属性对一组属性的依赖性称为平凡函数依赖性。
符号:如果B
是A
的子集,则A -> B
是平凡的函数依赖。
以下依赖也是平凡的:A -> A
和B -> B
。
例如:考虑一个包含两列Student_id
和Student_Name
的表。
{Student_Id, Student_Name} -> Student_Id
是一个平凡的函数依赖,因为Student_Id
是{Student_Id, Student_Name}
的子集。这是有道理的,因为如果我们知道Student_Id
和Student_Name
的值,那么可以唯一地确定Student_Id
的值。
另外,Student_Id -> Student_Id
和Student_Name -> Student_Name
也是平凡的依赖关系。
DBMS 中的非平凡函数依赖
原文: https://beginnersbook.com/2015/04/non-trivial-functional-dependency-in-dbms/
如果函数依赖X -> Y
在Y
不是X
的子集的情况下成立,那么这种依赖性称为非平凡的函数依赖性。
例如:
具有三个属性的员工表:emp_id
,emp_name
,emp_address
。
以下函数依赖是非平凡的:
emp_id -> emp_name
(emp_name
不是emp_id
的子集)emp_id -> emp_address
(emp_address
不是emp_id
的子集)
另一方面,以下依赖性是平凡的:
{emp_id, emp_name} -> emp_name
(emp_name
是{emp_id, emp_name}
的一个子集)
参考:平凡的函数依赖。
完全非平凡 FD:
如果 FD X -> Y
在X
交Y
为空的情况下为真,则该依赖性被认为是完全非平凡的函数依赖。
DBMS 中的多值依赖
原文: https://beginnersbook.com/2015/04/multivalued-dependency-in-dbms/
当表中存在多个独立多值属性时,会发生多值依赖。
例如:考虑一家自行车制造公司,每年在每个车型中生产两种颜色(黑色和白色)。
bike_model |
manuf_year |
color |
---|---|---|
M1001 | 2007 | Black |
M1001 | 2007 | Red |
M2012 | 2008 | Black |
M2012 | 2008 | Red |
M2222 | 2009 | Black |
M2222 | 2009 | Red |
这里的列manuf_year
和颜色彼此独立并依赖于bike_model
。在这种情况下,这两列可以说是多值的,取决于bike_model
。这些依赖关系可以表示如下:
bike_model ->> manuf_year
bike_model ->> color
DBMS 中的传递依赖
原文: https://beginnersbook.com/2015/04/transitive-dependency-in-dbms/
如果函数依赖性由两个函数依赖性间接形成,则称其是传递的。例如:
如果以下三个函数依赖项成立,则
X -> Z`是传递依赖:
X -> Y
Y !-> X
Y -> Z
注意:传递依赖只能在三个或更多属性的关系中发生。这种依赖性有助于我们在 3NF(第三范式)中对数据库进行标准化。
示例:让我们举一个例子来更好地理解它:
| Book | Author | Author_age |
| Game of Thrones | George R. R. Martin | 66 |
| Harry Potter | J. K. Rowling | 49 |
| Dying of the Light | George R. R. Martin | 66 |
{Book} ->{Author}
(如果我们知道这本书,我们知道作者姓名)
{Author} !-> {Book}
{Author} -> {Author_age}
因此,根据传递依赖的规则:{Book} -> {Author_age}
应该成立,这是有道理的,因为如果我们知道书名,我们就可以知道作者的年龄。
DBMS 中的范式:数据库中的 1NF,2NF,3NF 和 BCNF
原文: https://beginnersbook.com/2015/05/normalization-in-dbms/
范式是在数据库中组织数据以避免数据冗余,插入异常,更新异常和数据的过程。删除异常。让我们首先讨论异常,然后我们将用例子讨论正常形式。
DBMS 中的异常
数据库未范式时会发生三种类型的异常。这些是 - 插入,更新和删除异常。我们举一个例子来理解这一点。
示例:假设制造公司将员工详细信息存储在名为employee
的表中,该表具有四个属性:emp_id
用于存储员工的 id,emp_name
用于存储员工的姓名,emp_address
用于存储员工的地址,emp_dept
用于存储部门详细信息员工的工作方式。在某些时候,表看起来像这样:
emp_id |
emp_name |
emp_address |
emp_dept |
---|---|---|---|
101 | Rick | Delhi | D001 |
101 | Rick | Delhi | D002 |
123 | Maggie | Agra | D890 |
166 | Glenn | Chennai | D900 |
166 | Glenn | Chennai | D004 |
上表未范式。我们将看到当表未范式时我们面临的问题。
更新异常:在上表中,员工 Rick 有两行,因为他属于公司的两个部门。如果我们想要更新 Rick 的地址,那么我们必须在两行中更新相同的内容,否则数据将变得不一致。如果不知何故,正确的地址在一个部门更新,但在其他部门没有更新,那么根据数据库,Rick 将有两个不同的地址,这是不正确的,会导致数据不一致。
插入异常:假设一名新员工加入正在接受培训并且当前未分配到任何部门的公司,那么如果emp_dept
字段不允许空值,我们将无法将数据插入表中。
删除异常:假设,如果公司关闭部门 D890 的某个时间点,那么删除具有emp_dept
为 D890 的行也会删除员工 Maggie 的信息,因为她只被分配给该部门。
为了克服这些异常,我们需要范式数据。在下一节中,我们将讨论范式。
范式
以下是最常用的常规形式:
- 第一范式(1NF)
- 第二范式(2NF)
- 第三范式(3NF)
- Boyce Codd 范式(BCNF)
第一范式(1NF)
根据第一范式的规则,表的属性(列)不能包含多个值。它应该只包含原子值。
示例:假设公司想要存储其员工的姓名和联系方式。它创建一个如下所示的表:
emp_id |
emp_name |
emp_address |
emp_mobile |
---|---|---|---|
101 | Herschel | New Delhi | 8912312390 |
102 | Jon | Kanpur | 88121212129900012222 |
103 | Ron | Chennai | 7778881212 |
104 | Lester | Bangalore | 99900001238123450987 |
两名员工(Jon& Lester)有两个手机号码,因此公司将它们存储在您在上表中看到的相同字段中。
该表是不在 1NF 中,因为规则说“表的每个属性必须具有原子(单个)值”,员工的emp_mobile
值为Jon & Lester
违反了这条规则。
为了使表符合 1NF,我们应该有这样的数据:
emp_id |
emp_name |
emp_address |
emp_mobile |
---|---|---|---|
101 | Herschel | New Delhi | 8912312390 |
102 | Jon | Kanpur | 8812121212 |
102 | Jon | Kanpur | 9900012222 |
103 | Ron | Chennai | 7778881212 |
104 | Lester | Bangalore | 9990000123 |
104 | Lester | Bangalore | 8123450987 |
第二范式(2NF)
如果以下两个条件成立,则表示在 2NF 中:
- 表为 1NF(第一范式)
- 没有非主属性取决于表的任何候选键的适当子集。
不属于任何候选键的属性称为非主属性。
示例:假设学校想要存储教师的数据和他们教授的科目。他们创建了一个如下所示的表:由于教师可以教授多个科目,因此该表可以为同一位教师设置多行。
teacher_id |
subject |
teacher_age |
---|---|---|
111 | Maths | 38 |
111 | Physics | 38 |
222 | Biology | 38 |
333 | Physics | 40 |
333 | Chemistry | 40 |
候选键:{teacher_id, subject}
非主属性:teacher_age
该表在 1 NF 中,因为每个属性都有原子值。但是,它不在 2NF 中,因为非主属性teacher_age
仅依赖于teacher_id
,它是候选键的适当子集。这违反了 2NF 的规则,因为规则说“没有非主属性依赖于表的任何候选键的正确子集”。
为了使表符合 2NF,我们可以在两个表中打破它:
teacher_details
表:
teacher_id |
teacher_age |
---|---|
111 | 38 |
222 | 38 |
333 | 40 |
teacher_subject
表:
teacher_id |
subject |
---|---|
111 | Maths |
111 | Physics |
222 | Biology |
333 | Physics |
333 | Chemistry |
现在表符合第二范式(2NF)。
第三范式(3NF)
如果满足以下条件,则表设计为 3NF:
- 表必须是 2NF
- 应删除任何超键上非主要属性的传递函数依赖。
不属于任何候选键的属性称为非主属性。
换句话说,3NF 可以这样解释:如果表在 2NF 中,则表在 3NF 中,并且对于每个函数依赖X -> Y
至少满足下列条件之一:
X
是表的超键Y
是表的主要属性
作为候选键之一的一部分的属性称为主要属性。
示例:假设公司想要存储每个员工的完整地址,他们会创建一个名为employee_details
的表,如下所示:
| emp_id
| emp_name
| emp_zip
| emp_state
| emp_city
| emp_district
|
| --- | --- | --- | --- | --- |
| 1001 | John | 282005 | UP | Agra | Dayal Bagh |
| 1002 | Ajeet | 222008 | TN | Chennai | M-City |
| 1006 | Lora | 282007 | TN | Chennai | Urrapakkam |
| 1101 | Lilly | 292008 | UK | Pauri | Bhagwan |
| 1201 | Steve | 222999 | MP | Gwalior | Ratan |
超键:{emp_id}
,{emp_id, emp_name}
,{emp_id, emp_name, emp_zip}
...等
候选键:{emp_id}
非主属性:除emp_id
之外的所有属性都是非主,因为它们不是任何候选键的一部分。
在这里,emp_state
,emp_city
和emp_district
依赖于emp_zip
。并且,emp_zip
依赖于emp_id
,这使得非主属性(emp_state
,emp_city
和emp_district
)可传递地依赖于超键(emp_id
)。这违反了 3NF 的规则。
要使此表符合 3NF,我们必须将表拆分为两个表以删除传递依赖项:
员工表:
emp_id |
emp_name |
emp_zip |
---|---|---|
1001 | John | 282005 |
1002 | Ajeet | 222008 |
1006 | Lora | 282007 |
1101 | Lilly | 292008 |
1201 | Steve | 222999 |
employee_zip
表:
emp_zip |
emp_state |
emp_city |
emp_district |
---|---|---|---|
282005 | UP | Agra | Dayal Bagh |
222008 | TN | Chennai | M-City |
282007 | TN | Chennai | Urrapakkam |
292008 | UK | Pauri | Bhagwan |
222999 | MP | Gwalior | Ratan |
Boyce Codd 范式(BCNF)
它是 3NF 的高级版本,这也是它被称为 3.5NF 的原因。 BCNF 比 3NF 更严格。如果表是 3NF,则表符合 BCNF,对于每个函数依赖X -> Y
,X
应该是表的超键。
示例:假设有一家公司,员工在多个部门工作。他们存储这样的数据:
emp_id |
emp_nationality |
emp_dept |
dept_type |
dept_no_of_emp |
---|---|---|---|---|
1001 | Austrian | Production and planning | D001 | 200 |
1001 | Austrian | stores | D001 | 250 |
1002 | American | design and technical support | D134 | 100 |
1002 | American | Purchasing department | D134 | 600 |
上表中的函数依赖:
emp_id -> emp_nationality
emp_dept -> {dept_type,dept_no_of_emp}
候选键:{emp_id, emp_dept}
该表不在 BCNF 中,因为emp_id
和emp_dept
都不是键。
为了使表符合 BCNF,我们可以在三个表中打破这样的表:
emp_nationality
表:
emp_id |
emp_nationality |
---|---|
1001 | Austrian |
1002 | American |
emp_dept
表:
emp_dept |
dept_type |
dept_no_of_emp |
---|---|---|
Production and planning | D001 | 200 |
stores | D001 | 250 |
design and technical support | D134 | 100 |
Purchasing department | D134 | 600 |
emp_dept_mapping
表:
emp_id |
emp_dept |
---|---|
1001 | Production and planning |
1001 | stores |
1002 | design and technical support |
1002 | Purchasing department |
函数依赖:
emp_id -> emp_nationality
emp_dept -> {dept_type, dept_no_of_emp}
候选键:
- 第一个表:
emp_id
- 第二个表:
emp_dept
- 第三个表:
{emp_id, emp_dept}
现在这是在 BCNF 中,因为在函数依赖中左侧部分是关键。
DBMS 中的事务管理
原文: https://beginnersbook.com/2017/09/transaction-management-in-dbms/
事务是一组逻辑相关的操作。例如,您正在将资金从您的银行帐户转移到您朋友的帐户,操作集将如下所示:
简单事务示例
- 阅读您的账户余额
- 扣除余额中的金额
- 将余额写入您的账户
- 读取您朋友的账户余额
- 将金额添加到他的账户余额
- 将新的更新余额写入其账户
这整组操作可以称为事务。虽然我已在上面的示例中向您展示了读取,写入和更新操作,但事务可以具有读取,写入,插入,更新,删除等操作。
在 DBMS 中,我们写下以下 6 个步骤的事务:
假设您的账户是 A 而您朋友的账户是 B,您要从 A 转移 10000 到 B,事务的步骤是:
1. R(A);
2. A = A - 10000;
3. W(A);
4. R(B);
5. B = B + 10000;
6. W(B);
在上述事务中 R
是指读操作, W
是指写操作。
操作之间的事务失败
现在我们了解什么是事务,我们应该了解与之相关的问题。
事务期间可能发生的主要问题是在完成集合中的所有操作之前事务可能会失败。这可能是由于电源故障,系统崩溃等原因造成的。这是一个严重的问题,可能会使数据库处于不一致状态。假设事务在第三次操作后失败(参见上面的示例),那么金额将从您的帐户中扣除,但您的朋友将不会收到该金额。
为了解决这个问题,我们有以下两个操作
提交:如果事务中的所有操作都成功完成,则永久地将这些更改提交到数据库。
回滚:如果任何操作失败,则回滚之前操作完成的所有更改。
即使这些操作可以帮助我们避免在事务期间可能出现的几个问题,但是当两个事务同时运行时它们是不够的。要处理这些问题,我们需要了解数据库 ACID 属性。
DBMS 中的 ACID 属性
原文: https://beginnersbook.com/2015/04/acid-properties-in-dbms/
为了确保事务期间数据的完整性(事务是一个更新各种数据项的程序单元,请在此处阅读更多相关信息),数据库系统维护以下属性。这些属性被广泛称为 ACID 属性:
- 原子性 :此属性确保事务的所有操作都反映在数据库中或不反映。让我们举一个银行系统的例子来理解这一点:假设账户 A 的余额为 400 美元& B 有 700 美元。账号 A 正在向账户 B 转账 100 美元。这是一个有两个操作的事务 a)从 A 的余额中扣除 100 美元 b)创建 100 美元到 B 的余额。假设第一次操作成功通过而第二次失败,在这种情况下 A 的余额为 300 $而 B 则为 700 $而不是 800 $。这在银行系统中是不可接受的。如果事务在没有执行任何操作的情况下失败,或者它应该处理这两个操作。原子性属性确保了这一点。
- 一致性:为了保持数据库的一致性,事务的执行应该孤立地进行(这意味着当事务已经运行时,不应该同时运行其他事务)。例如,账户 A 的余额为 400 美元,它将 100 美元转账到账户 B& C 两者。所以我们在这里有两笔事务。假设这些事务同时运行,两笔事务均为 400 美元余额,在这种情况下,A 的最终余额为 300 美元而不是 200 美元。这是错的。如果事务是在隔离的情况下运行,那么第一笔事务成功后,第二笔事务就会读取正确的余额 300 美元(在扣除 100 美元之前)。
- 隔离:对于每对事务,只有当另一个事务完成执行时,才会开始执行一个事务。我已经在上面的一致性属性中讨论过隔离的例子。
- 持久性:一旦事务成功完成,即使系统出现故障,它对数据库所做的更改也应该是永久性的。数据库系统的恢复管理组件可确保事务的持久性。
DBMS 优于文件系统的优点
在本指南中,我们将讨论什么是文件处理系统以及数据库管理系统如何比文件处理系统更好。
文件系统的缺点
-
数据冗余:数据冗余是指数据的重复,假设我们正在管理学生注册两门课程的大学数据,在这种情况下相同的学生详细信息将被存储两次,将需要更多的存储空间。数据冗余通常会导致更高的存储成本和更短的访问时间。
-
数据不一致:数据冗余导致数据不一致,让我们采取与上面相同的例子,一个学生注册两个课程,我们有两个学生地址,现在让我们说学生要求改变他的地址,如果地址在一个地方而不是在所有记录上更改,那么这可能导致数据不一致。
-
数据隔离:由于数据分散在各种文件中,文件可能采用不同的格式,因此编写新的应用以检索适当的数据很困难。
-
对应用的依赖:更改文件会导致应用发生变化。
-
原子性问题: 事务的原子性代表“要么全部要么没有”,它的意思是要么事务的所有操作都执行,要么都没有。
例如:让我们说 Steve 将 100 美元转移到 Negan 的账户。此事务包括多项操作,例如 Steve 的账户转出 100 美元,Negan 的账户转入 100。像任何其他设备一样,计算机系统可能会失败,让我们说它在第一次操作后失败然后在那种情况下,Steve 的帐户将被扣除 100 美元,但是这笔金额没有记入 Negan 的帐户,在这种情况下,操作的回滚应该发生用于保持事务的原子性。难以在文件处理系统中实现原子性。
-
数据安全:应保护数据免受未经授权的访问,例如,大学的学生不应该看到教师的工资单细节,这种安全限制很难在文件处理系统中应用。
DBMS 优于文件系统的优点
数据库管理系统对比文件系统有几个优点。其中一些如下:
- 无冗余数据:数据标准化删除了冗余。没有数据重复可以节省存储空间并缩短访问时间。
- 数据一致性和完整性:正如我们之前讨论的那样,数据不一致的根本原因是数据冗余,因为数据范式处理数据冗余,数据不一致也作为其中的一部分被处理。
- 数据安全:在数据库系统中应用访问约束更容易,只有授权用户才能访问数据。每个用户都有不同的访问权限,因此可以保护数据免受身份盗窃,数据泄漏和数据滥用等问题的影响。
- 隐私:有限访问意味着数据隐私。
- 轻松访问数据 - 数据库系统以这样的方式管理数据,以便在快速响应时间内轻松访问数据。
- 轻松恢复:由于数据库系统保留了数据备份,因此在发生故障时更容易完全恢复数据。
- 灵活:数据库系统比文件处理系统更灵活。
DBMS 的缺点:
- 与文件系统相比,DBMS 实现成本较高
- 复杂性:数据库系统很难理解
- 性能:数据库系统是通用的,使它们适用于各种应用。但是,此功能会影响某些应用的性能
DBMS 事务状态
原文: https://beginnersbook.com/2018/12/dbms-transaction-states/
在本指南中,我们将讨论 DBMS 中事务的状态。 DBMS 中的事务可以处于以下状态之一。
DBMS 事务状态图
让我们一个一个地讨论这些状态。
活跃状态
正如我们在 DBMS 事务介绍中所讨论的那样,事务是一系列操作。如果一个事务正在执行,那么它被称为处于活动状态。执行哪个步骤无关紧要,除非事务正在执行,否则它将保持活动状态。
故障状态
如果事务正在执行并且发生故障(硬件故障或软件故障),则事务将从活动状态进入故障状态。
部分提交状态
正如我们在上图中所看到的,当事务中存在读写操作时,事务从活动状态进入“部分提交”状态。
事务包含许多读写操作。一旦整个事务成功执行,事务就进入部分提交状态,我们在主存储器(本地存储器)而不是实际数据库上执行所有读写操作。
我们拥有此状态的原因是因为事务在执行期间可能会失败,因此如果我们在实际数据库而不是本地内存中进行更改,则数据库可能会在出现任何故障时保持不一致状态。 此状态帮助我们回滚在执行过程中发生故障时对数据库所做的更改。
提交状态
如果事务成功完成执行,则在部分提交状态期间在本地存储器中进行的所有更改将永久存储在数据库中。您还可以在上图中看到,当一切成功时,事务从部分提交状态变为已提交状态。
失败状态
如上所述,如果事务在执行期间失败,则事务将进入失败状态。对本地内存(或缓冲区)所做的更改将回滚到先前的一致状态,并且事务将从失败状态进入中止状态。请参阅图表以查看失败和中止状态之间的相互作用。
DBMS 调度和调度类型
我们知道事务是一组指令,这些指令在数据库上执行操作。当多个事务同时运行时,需要有一个执行操作的序列,因为一次只能对数据库执行一个操作。这一系列操作称为 调度 。
让我们举个例子来了解 DBMS 中的调度是什么。
DBMS 调度示例
以下操作顺序是调度。这里我们有两个事务T1
和T2
同时运行。
此调度确定将在数据库上执行的操作的确切顺序。在这个例子中,事务T1
的所有指令都在事务T2
的指令之前执行,但是这并不总是必要的,我们可以有各种类型的调度,我们将在本文中讨论。
T1 T2
---- ----
R(X)
W(X)
R(Y)
R(Y)
R(X)
W(Y)
DBMS 中的调度类型
我们在 DBMS 中有各种类型的调度。让我们逐一讨论它们。
串行调度
在串行调度中,在开始执行另一个事务之前完全执行事务。换句话说,您可以说在串行调度中,事务在当前正在运行的事务完成执行之前不会开始执行。这种类型的事务执行也称为非交错执行。我们上面看到的例子是连续调度。
让我们再看一个例子。
串行调度示例
这里R
表示读操作,W
表示写操作。在此示例中,事务T2
在事务T1
完成之前不会开始执行。
T1 T2
---- ----
R(A)
R(B)
W(A)
commit
R(B)
R(A)
W(B)
commit
严格调度
在严格调度中,如果事务的写入操作先于另一个事务的冲突操作(读取或写入操作),则此类事务的提交或中止操作也应该在其他事务的冲突操作之前。
让我们举个例子。
严格调度示例
假设我们有两个事务Ta
和Tb
。事务Ta
的写入操作在事务Tb
的读取或写入操作之前,因此事务Ta
的提交或中止操作也应该在读取或写入Tb
之前。
Ta Tb
----- -----
R(X)
R(X)
W(X)
commit
W(X)
R(X)
commit
这里,Ta
的写操作W(X)
在Tb
的冲突操作(读或写操作)之前,因此Tb
的冲突操作必须等待Ta
的提交操作。
无级联调度
在无级联调度中,如果事务要对某个值执行读操作,则必须等到执行写入该值的事务提交。
无级联调度示例
例如,假设我们有两个事务Ta
和Tb
。Tb
将在Ta
的W(X)
之后读取值X
,然后Tb
必须在读取X
之前等待事务Ta
的提交操作。
Ta Tb
----- -----
R(X)
W(X)
W(X)
commit
R(X)
W(X)
commit
可恢复的调度
在可恢复调度中,如果事务正在读取已由某个其他事务更新的值,则此事务只能在提交正在更新值的其他事务之后提交。
可恢复调度示例
这里Tb
在Ta
使用W(X)
在X
中进行了更改之后对X
执行读取操作,因此Tb
只能在Ta
的提交操作之后提交。
Ta Tb
----- -----
R(X)
W(X)
R(X)
W(X)
R(X)
commit
commit
DBMS 可串行化
当多个事务同时运行时,数据库可能会处于不一致状态。可串行化是一个概念,可以帮助我们检查哪些调度是可串行化的。可串行化的调度是始终使数据库保持一致状态的调度。
什么是可串行化的调度?
可串行化的调度始终使数据库保持一致状态。 串行调度始终是可串行化的调度,因为在串行调度中,事务仅在另一个事务完成执行时启动。但是,需要检查可串行化的非串行调度。
如果 n 个事务的非串行调度等同于那些 n 个事务的串行调度,则称其为可串行化调度。串行调度不允许并发,一次只执行一个事务,另一个事件在已经运行的事务完成时启动。
可串行化的类型
可串行化有两种类型。
DBMS 冲突可串行化
原文: https://beginnersbook.com/2018/12/dbms-conflict-serializability/
在 DBMS 调度指南中,我们了解到有两种类型的调度 - 串行和调度。非串联。串行调度不支持并发执行事务,而非串行调度支持并发。我们还在可串行化 教程中了解到,非串行调度可能会使数据库处于不一致状态,因此我们需要检查这些非串行调度以获得可串行化。
冲突可串行化是可串行化类型之一,可用于检查非串行调度是否可冲突串行化。
什么是冲突可串行化?
如果我们可以在交换其非冲突操作后将其转换为串行调度,则调度称为冲突可串行化。
冲突的操作
如果它们满足以下三个条件,则说两个操作存在冲突:
- 这两项业务都属于不同的事务。
- 两个操作都在同一个数据项上运行。
- 至少有一个操作是写操作。
让我们看一些例子来理解这一点:
例 1:事务T1
的操作W(X)
和事务T2
的操作R(X)
是冲突操作,因为它们满足上述所有三个条件。它们属于不同的事务,它们正在处理相同的数据项 X,这是写操作中的一个操作。
示例 2:类似地,T1
的操作W(X)
和T2
的W(X)
是冲突操作。
例 3:T1
的操作W(X)
和T2
的W(Y)
是非冲突操作,因为两个写操作都不在同一数据项上工作,因此这些操作不满足第二个条件。
例 4:类似地,T1
的R(X)
和T2
的R(X)
是非冲突操作,因为它们都不是写操作。
示例 5:类似地,T1
的R(X)
和T1
的W(X)
是非冲突操作,因为两个操作属于同一事务T1
。
冲突等价调度
如果在交换非冲突操作之后可以将一个调度转换为其他调度,则称两个调度是冲突等效。
冲突可串行化检查
让我们检查一个调度是否可以冲突串行化。如果调度冲突等同于其序列调度,则称为冲突可串行化调度。让我们举几个调度的例子。
冲突可串行化的示例
让我们考虑这个调度:
T1 T2
----- ------
R(A)
R(B)
R(A)
R(B)
W(B)
W(A)
要将此调度转换为连续调度,我们必须将事务T2
的R(A)
操作与事务T1
的W(A)
操作交换。但是我们不能交换这两个操作,因为它们是冲突操作,因此我们可以说这个给定的调度是而不是冲突可串行化。
让我们再看一个例子:
T1 T2
----- ------
R(A)
R(A)
R(B)
W(B)
R(B)
W(A)
让交换非冲突操作:
在交换T1
的R(A)
和T2
的R(A)
后,我们得到:
T1 T2
----- ------
R(A)
R(A)
R(B)
W(B)
R(B)
W(A)
在交换T1
的R(A)
和T2
的R(B)
后,我们得到:
T1 T2
----- ------
R(A)
R(B)
R(A)
W(B)
R(B)
W(A)
在交换T1
的R(A)
和T2
的W(B)
后,我们得到:
T1 T2
----- ------
R(A)
R(B)
W(B)
R(A)
R(B)
W(A)
在交换所有非冲突操作后,我们终于得到了一个连续的调度,因此我们可以说给定的调度是冲突可串行化。
DBMS 查看可串行化
原文: https://beginnersbook.com/2018/12/dbms-view-serializability/
在上一个教程中,我们学习了冲突可串行化。在本文中,我们将讨论另一种可串行化,即 查看可串行化 。
什么是查看可串行化?
查看可串行化是一个查找给定调度视图是否可串行化的过程。
要检查给定的调度是否可视化串行化,我们需要检查给定的调度是否对其序列调度 查看等价。让我们举个例子来理解我的意思。
给定调度:
T1 T2
----- ------
R(X)
W(X)
R(X)
W(X)
R(Y)
W(Y)
R(Y)
W(Y)
以上给定调度的串行调度:
我们知道在串行调度中,只有在当前运行的事务完成时才会启动事务。所以上面给出的调度的连续调度如下所示:
T1 T2
----- ------
R(X)
W(X)
R(Y)
W(Y)
R(X)
W(X)
R(Y)
W(Y)
如果我们能够证明给定的调度对其连续调度 查看等价,那么给定的调度称为视图可串行。
为什么我们需要查看可串行化?
我们知道,串行调度永远不会使数据库处于不一致状态,因为没有并发事务执行。但是,非串行调度可能会使数据库处于不一致状态,因为有多个事务同时运行。通过检查给定的非串行调度是否可视化串行化,我们确保它是一致的调度。
您可能想知道不是检查非串行调度是否可串行化,我们不能一直有串行调度吗?答案是否定的,因为事务的并发执行充分利用了系统资源,并且与串行调度相比要快得多。
查看等效
让我们学习如何检查两个调度是否相同。
如果它们满足以下所有条件,则称两个调度T1
和T2
是等效视图:
- 初始读取:事务中每个数据项的初始读取必须在两个调度中都匹配。例如,如果事务
T1
在调度S1
中的事务T2
之前读取数据项X
,则在调度S2
中,T1
应该在T2
之前读取X
。
读取与初始读取:您可能会对术语初始读取感到困惑。这里初始读取意味着对数据项的第一次读取操作,例如,数据项X
可以在调度中多次读取,但是对X
的第一次读取操作称为初始读取。一旦我们在同一篇文章的下一部分中得到示例,这将更加清晰。
-
最终写入:每个数据项的最终写操作必须在两个调度中都匹配。例如,数据项
X
最后由事务T1
在调度S1
中写入,然后在S2
中,对X
的最后一次写操作应该由事务T1
执行。 -
更新读取:如果在调度
S1
中,事务T1
正在读取由T2
更新的数据项,则在调度S2
中,T1
应该在相同数据项上的T2
写操作之后读取该值。例如,在调度S1
中,T1
在X
上执行写入操作后对X
执行读取操作,然后在S2
中,T1
在T2
执行写入操作后读取X
。
查看可串行
如果调度视图等同于其序列调度,那么给定的调度称为查看可串行。让我们举个例子。
查看可串行化示例
让我们检查一下可串行化的三个条件:
初始读取
在调度S1
中,事务T1
首先读取数据项X
.在S2
中,事务T1
首先读取数据项X
.
让我们检查Y
.在调度S1
中,事务T1
首先读取数据项Y
.在S2
中,Y
上的第一次读操作由T1
执行。
我们检查了数据项X
和在S1
和S1
中满足Y
和初始读取条件。
最终写入
在调度S1
中,X
上的最终写操作由事务T2
完成。在S2
中,事务T2
也在X
上执行最终写入。
让我们检查Y
.在调度S1
中,Y
上的最终写操作由事务T2
完成。在调度S2
中,Y
上的最终写入由T2
完成。
我们检查了数据项X
和Y
,在S1
和S2
中,最终写入条件得到满足。
更新读取
在S1
中,事务 T2 读取由 T1 写入的 X 的值。在 S2 中,相同的事务 T2 在 T1 写入之后读取 X.
在S1
中,事务T2
读取由T1
写入的Y
的值。在S2
中,相同的事务T2
在T1
更新之后读取Y
的值。
两个调度也满足更新读取条件。
结果:由于在该示例中满足检查两个调度是否是视图等效的所有三个条件,这意味着S1
和S2
是视图等效的。而且,正如我们所知,调度S2
是S1
的连续调度,因此我们可以说调度S1
是视图可串行化调度。
DBMS 中的死锁
死锁是一个条件,其中两个或多个任务正在等待彼此以便完成,但任务都不愿意放弃其他任务所需的资源。在这种情况下,任务都没有完成,并且永远处于等待状态。
科夫曼条件
科夫曼说明发生死锁的四个条件。如果满足以下所有条件,则可能发生死锁。
- 互斥条件:必须至少有一个资源一次不能被多个进程使用。
- 保持和等待条件:持有资源的进程可以请求系统中其他进程持有的其他资源。
- 无抢占条件:无法强制从进程中获取资源。只有进程才能释放它所持有的资源。
- 循环等待条件:一个进程正在等待第二个进程持有的资源而第二个进程正在等待第三个进程的情况......等等,最后一个进程正在等待第一个进程。从而制作一个循环链等待。
死锁处理
忽略死锁(鸵鸟算法)
那会让你笑吗?您可能想知道如何在死锁处理下忽略死锁。但是为了让你知道你在 PC 上使用的窗口,使用这种死锁处理方法,这是有时它会挂起的原因,你必须重新启动才能使它工作。不仅 Windows 而且 UNIX 也使用这种方法。
问题是为什么?为什么不用处理死锁而忽略它以及为什么这被称为鸵鸟算法呢?
好!让我先回答第二个问题,这就是所谓的鸵鸟算法,因为在这种方法中我们忽略了死锁并假装它永远不会发生,就像鸵鸟的行为“把头埋在沙子中假装没有问题”。
让我们讨论为什么我们忽略它:当认为死锁非常罕见并且死锁处理的成本更高时,在这种情况下忽略是比处理它更好的解决方案。例如:让我们以操作系统为例 - 如果时间需要处理死锁高于需要重新启动窗口的时间,那么考虑到死锁在 Windows 中非常罕见,重启将是首选。
死锁检测
资源调度程序是一种保持对进程分配和请求的资源的跟踪。因此,如果存在死锁,则资源调度程序已知它。这是检测到死锁的方式。
检测到死锁后,将通过以下方法进行更正:
- 终止死锁中涉及的进程:一个接一个地终止死锁或终止进程中涉及的所有进程,直到死锁被解决,这可能是解决方案,但这两种方法都不好。终止所有进程的成本很高,进程完成的部分工作会丢失。逐个终止需要花费大量时间,因为每次进程终止时,都需要检查死锁是否已解决。因此,最佳方法是在死锁条件期间终止它们时考虑进程年龄和优先级。
- 资源抢占:另一种方法可以是抢占资源并将其分配给其他进程,直到解决了死锁。
死锁预防
我们已经了解到,如果所有四个科夫曼条件都成立,则会发生死锁,因此阻止其中的一个或多个可以防止死锁。
- 删除互斥:所有资源必须是可共享的,这意味着一次可以有多个进程获取资源。这种方法几乎是不可能的。
- 删除保持和等待条件:如果进程在开始之前获取了所需的所有资源,则可以将其删除。另一种删除此方法的方法是在进程持有时不执行请求资源的规则。
- 抢占资源:从进程中抢占资源可能导致回滚,因此需要避免这种情况以保持系统的一致性和稳定性。
- 避免循环等待条件:如果资源在层次结构中维护,并且进程可以按优先级递增的顺序保存资源,则可以避免这种情况。这避免了循环等待。另一种方法是强制每个进程规则使用一个资源 - 进程可以在释放当前所拥有的资源后请求资源。这避免了循环等待。
死锁避免
如果以避免发生死锁的方式分配资源,则可以避免死锁。有两种算法可以避免死锁。
- 等待/死亡
- 死亡/等待
以下是每种算法的资源分配的表表示。这两种算法都考虑了进程时代,同时确定了避免死锁的最佳资源分配方式。
| | 等待/死亡 | 死亡/等待 |
| --- | --- |
| 旧进程需要新进程持有的资源 | 旧进程等待 | 新进程死亡 |
| 新进程需要旧进程持有的资源 | 旧进程死亡 | 新进程等待 |
一个着名的死锁避免算法是 银行家算法。
DBMS 中的并发控制
原文: https://beginnersbook.com/2017/09/concurrency-control-in-dbms/
当同时运行多个事务时,可能会发生冲突,从而使数据库处于不一致状态。为了处理这些冲突,我们需要 DBMS 中的并发控制,它允许事务同时运行,但以这样的方式处理它们,以便数据的完整性保持不变。
我们举一个例子来理解我在这里说的话。
冲突示例
你和你的兄弟有一个联合银行账户,你可以从中提取资金。现在让我们说你们两个同时去同一家银行的不同分行尝试提取 5000 INR,你的联名账户只有 6000 余额。现在,如果我们没有并发控制,你们两个可以同时获得 5000 INR,但是一旦两个事务完成,账户余额将是-4000,这是不可能的,并使数据库处于不一致状态。
我们需要以某种方式控制事务的东西,允许事务同时运行,但保持数据的一致性以避免此类问题。
冲突解决方案:锁
锁是一种确保维护数据完整性的机制。在访问数据时可以放置两种类型的锁,以便在我们处理数据时并发事务不会改变数据。
- 共享锁(
S
) - 独占锁(
X
)
1. 共享锁(S
):当我们读取数据时放置共享锁,可以在数据上放置多个共享锁,但是当放置共享锁时,不能放置独占锁。
例如,当两个事务正在读取史蒂夫的账户余额时,让他们通过放置共享锁来读取,但如果另一个事务想要通过放置独家锁来更新史蒂夫的账户余额,则在读取完成之前不要允许它。
2. 独占锁(X
):当我们想要读取和写入数据时,放置独占锁。此锁允许读取和写入操作。一旦将此锁放在数据上,就不会对数据放置其他锁(共享或独占),直到释放独占锁。
例如,当一个事务想要更新史蒂夫的账户余额时,让它通过放置X
锁来做,但如果第二个事务想要读取数据(S
锁)不允许它,如果另一个事务想要写入数据(X
锁)也不允许这样做。
所以基于此,我们可以创建一个这样的表:
锁兼容性矩阵
__________________________
| | S | X |
|-------------------------
| S | True | False |
|-------------------------
| X | False | False |
--------------------------
如何读取这个矩阵?:
有两行,第一行表示当放置S
锁时,可以获取另一个S
锁,因此它被标记为true
但是没有可以获得独占锁标记为假。
在第二行中,当获取X
锁时,既不能获取S
也不能获得X
锁,因此两者都标记为假。
DBMS 架构
在之前的教程中,我们学习了 DBMS 的基础知识。在本指南中,我们将看到 DBMS 架构。数据库管理系统架构将帮助我们理解数据库系统的组件及其之间的关系。
DBMS 的架构取决于它运行的计算机系统。例如,在客户端 - 服务器 DBMS 架构中,服务器计算机上的数据库系统可以执行客户端计算机发出的多个请求。我们将借助图表来理解这种通信。
DBMS 架构的类型
DBMS 架构有三种类型:
- 单层架构
- 双层架构
- 三层架构
1. 单层架构
在这种类型的架构中,数据库在客户端计算机上很容易获得,客户端发出的任何请求都不需要网络连接来对数据库执行操作。
例如,假设您要从数据库中获取员工的记录,并且数据库在您的计算机系统上可用,因此获取员工详细信息的请求将由您的计算机完成,并且您的数据将由你的电脑从数据库中获取。这种类型的系统通常称为本地数据库系统。
2. 双层架构
在双层架构中,数据库系统存在于服务器机器上,DBMS 应用存在于客户机上,这两台机器通过可靠的网络相互连接,如上图所示。
每当客户端机器使用诸如 sql 之类的查询语言发出访问服务器上存在的数据库的请求时,服务器就会对数据库执行请求并将结果返回给客户端。 JDBC,ODBC 等应用连接接口用于服务器和客户端之间的交互。
3. 三层架构
在三层架构中,客户端计算机和服务器计算机之间存在另一层。在该架构中,客户端应用不直接与服务器机器上存在的数据库系统通信,而是客户端应用与服务器应用通信,并且服务器应用在内部与服务器上存在的数据库系统通信。
DBMS - 三层架构
原文: https://beginnersbook.com/2018/11/dbms-three-level-architecture/
在上一篇教程中,我们看到了 DBMS 架构 - 一层,两层和三层。在本指南中,我们将详细讨论三层 DBMS 架构。
DBMS 三层架构图
该架构有三个层次:
- 外部层
- 概念层
- 内部层
1. 外部层
它也被称为视图层。此层次称为“视图”的原因是因为多个用户可以在此层次查看所需数据,这些数据是在概念和内部层次映射的帮助下从数据库内部获取的。
用户不需要知道数据库架构细节,例如数据结构,表定义等。用户只关心从数据库中获取后返回到视图层次的数据(存在于内部层次)。
外部层次是三层 DBMS 架构的“顶层”。
2. 概念层
它也被称为逻辑层。数据库的整体设计,如数据之间的关系,数据模式等都在这个层次上进行了描述。
数据库约束和安全性也在此层次的架构中实现。此层次由 DBA(数据库管理员)维护。
3. 内部层
此层次也称为物理层。此层次描述了数据实际存储在存储设备中的方式。此层次还负责为数据分配空间。这是架构的最低层次。
DBMS 中的数据视图
抽象是数据库系统的主要特征之一。隐藏用户不相关的细节并向用户提供数据的抽象视图,有助于用户轻松高效地与数据库交互。在前面的教程中,我们讨论了三层 DBMS 架构,该架构的顶层是“视图层次”。视图层次向用户提供“数据”视图,并隐藏用户无关的详细信息,如数据关系,数据库模式,约束,安全性等。
要完全理解数据视图,您必须具备数据抽象以及实例和模式的基本知识。请参阅这两个教程以详细了解它们。
DBMS 中的数据抽象
原文: https://beginnersbook.com/2015/04/levels-of-abstraction-in-dbms/
数据库系统由复杂的数据结构组成。为了简化用户与数据库的交互,开发人员隐藏了用户无关的内部细节。这种从用户隐藏不相关细节的过程称为数据抽象。
我们有三个抽象层次:
物理层:这是数据抽象的最低层次。它描述了数据实际存储在数据库中的方式。您可以在此级别获取复杂的数据结构详细信息。
逻辑层:这是 3 级数据抽象架构的中间层。它描述了数据库中存储的数据。
视图层:最高级别的数据抽象。此级别描述用户与数据库系统的交互。
示例:假设我们将客户信息存储在客户表中。在物理层,这些记录可以描述为内存中的存储块(字节,KB,TB 等)。这些细节通常对程序员来说是隐藏的。
在逻辑层,这些记录可以被描述为字段和属性以及它们的数据类型,它们之间的关系可以在逻辑上实现。程序员通常在这个级别工作,因为他们知道有关数据库系统的这些事情。
在视图层,用户只需在 GUI 的帮助下与系统交互并在屏幕上输入详细信息,他们不知道数据的存储方式和存储的数据;这些细节对他们来说是隐藏的。
DBMS 中的实例和模式
原文: https://beginnersbook.com/2015/04/instance-and-schema-in-dbms/
在本指南中,我们将了解 DBMS 中的实例和模式。
DBMS 架构
模式的定义:数据库的设计称为模式。架构有三种类型:物理架构,逻辑架构和视图架构。
例如:在下图中,我们有一个模式,显示三个表之间的关系:Course
,Student
和Section
。该图仅显示数据库的设计,它不显示这些表中存在的数据。模式只是数据库的结构视图(设计),如下图所示。
物理层面的数据库设计称为物理模式,在此级别描述数据如何存储在存储块中。
逻辑层面数据库的设计称为逻辑模式,程序员和数据库管理员在这个级别工作,在这个级别数据可以描述为某些类型的数据记录,存储在数据结构中,但因为数据结构的实现,内部细节在此级别隐藏(在物理级别可用)。
视图级数据库的设计称为视图模式。这通常描述了最终用户与数据库系统的交互。
要了解有关这些模式的更多信息,请参阅 3 级数据抽象。
DBMS 实例
实例的定义:在特定时刻存储在数据库中的数据称为数据库实例。数据库模式定义属于特定数据库的表中的变量声明;这些变量在某个时刻的值称为该数据库的实例。
例如,假设我们在数据库中有一个表Student
,今天该表有 100 条记录,所以今天数据库的实例有 100 条记录。假设我们明天将在此表中添加另外 100 条记录,因此明天数据库实例将在表中有 200 条记录。简而言之,在特定时刻,存储在数据库中的数据称为实例,当我们从数据库添加或删除数据时,该实例会随时间而变化。