数据库基础
关系型数据库
关系数据库特点
- 理论基础:关系代数(关系运算、集合论、一阶谓词逻辑)。
- 具体表象:用二维表(有行和列)组织数据。
- 编程语言:结构化查询语言(SQL)。
ER 模型(实体关系模型)和概念模型图
ER 模型,全称为实体关系模型(Entity-Relationship Model),由美籍华裔计算机科学家陈品山先生提出,是概念数据模型的高层描述方式,如下图所示。

- 实体 - 矩形框
- 属性 - 椭圆框
- 关系 - 菱形框
- 重数 - 1:1(一对一) / 1:N(一对多) / M:N(多对多)
实际项目开发中,我们可以利用数据库建模工具(如:PowerDesigner)来绘制概念数据模型(其本质就是 ER 模型),然后再设置好目标数据库系统,将概念模型转换成物理模型,最终生成创建二维表的 SQL(很多工具都可以根据我们设计的物理模型图以及设定的目标数据库来导出 SQL 或直接生成数据表)。
关系数据库产品
- Oracle - 目前世界上使用最为广泛的数据库管理系统,作为一个通用的数据库系统,它具有完整的数据管理功能;作为一个关系数据库,它是一个完备关系的产品;作为分布式数据库,它实现了分布式处理的功能。在 Oracle 最新的 12c 版本中,还引入了多承租方架构,使用该架构可轻松部署和管理数据库云。
- DB2 - IBM 公司开发的、主要运行于 Unix(包括 IBM 自家的 AIX)、Linux、以及 Windows 服务器版等系统的关系数据库产品。DB2 历史悠久且被认为是最早使用 SQL 的数据库产品,它拥有较为强大的商业智能功能。
- SQL Server - 由 Microsoft 开发和推广的关系型数据库产品,最初适用于中小企业的数据管理,但是近年来它的应用范围有所扩展,部分大企业甚至是跨国公司也开始基于它来构建自己的数据管理系统。
- MySQL - MySQL 是开放源代码的,任何人都可以在 GPL(General Public License)的许可下下载并根据个性化的需要对其进行修改。MySQL 因为其速度、可靠性和适应性而备受关注。
- PostgreSQL - 在 BSD 许可证下发行的开放源代码的关系数据库产品。
RDBMS 术语
- 数据库: 数据库是一些关联表的集合。
- 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
- 列: 一列 (数据元素) 包含了相同类型的数据, 例如邮政编码的数据。
- 行:一行(元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
- 冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。
- 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
- 外键:外键用于关联两个表。
- 复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。
- 索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
- 参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。
如 MySQL 为关系型数据库 (Relational Database Management System), 这种所谓的 " 关系型 " 可以理解为 " 表格 " 的概念, 一个关系型数据库由一个或数个表格组成, 如图所示的一个表格:
- 表头 (header): 每一列的名称;
- 列 (col): 具有相同数据类型的数据的集合;
- 行 (row): 每一行用来描述某条记录的具体信息;
- 值 (value): 行的具体信息, 每个值必须与该列的数据类型相同;
- 键 (key): 键的值在当前列中具有唯一性。
数据库范式?
范式理论是设计关系型数据库中二维表的指导思想。
- 第一范式:数据表的每个列的值域都是由原子值组成的,不能够再分割。
- 第二范式:数据表里的所有数据都要和该数据表的键(主键与候选键)有完全依赖关系。
- 第三范式:所有非键属性都只和候选键有相关性,也就是说非键属性之间应该是独立无关的。
实际工作中,出于效率的考虑,我们在设计表时很有可能做出反范式设计,即故意降低方式级别,增加冗余数据来获得更好的操作性能。
第一范式
第⼀范式就是属性不可分割,每个字段都应该是不可再拆分的。⽐如⼀个字段是姓名(NAME),在国内的话通常理解都是姓名是⼀个不可再拆分的单位,这时候就符合第⼀范式;但是在国外的话还要分为 FIRST NAME 和 LASTNAME,这时候姓名这个字段就是还可以拆分为更⼩的单位的字段,就不符合第⼀范式了
第二范式(主键约束)
第⼆范式就是要求表中要有主键,表中其他其他字段都依赖于主键,因此第二范式只要记住主键约束就好了。
比如说有⼀个表是学⽣表,学⽣表中有⼀个值是唯⼀的字段学号,那么学⽣表中的其他所有字段都可以根据这个学号字段去获取,依赖主键的意思也就是相关的意思,因为学号的值是唯⼀的,因此就不会造成存储的信息对不上的问题,即学⽣ 001 的姓名不会存到学⽣ 002 那⾥去 。
第三范式(外键约束)
第三范式就是要求表中不能有其他表中存在的、存储相同信息的字段,通常实现是通过外键去建⽴关联,因此第三范式只要记住外键约束就好了。
比如说有⼀个表是学⽣表,学⽣表中有学号,姓名等字段,那如果要把他的系编
号,系主任也存到这个学⽣表中,那就会造成数据⼤量冗余,⼀是这些信息在系信息表中已存在,⼆是系中有 1000 个学⽣的话这些信息就要存 1000 遍。因此第三范式的做法是在学⽣表中增加⼀个系编号的字段做外键,与系信息表做关联。
数据完整性
- 实体完整性 - 每个实体都是独一无二的
- 主键(
primary key) / 唯一约束(unique)
- 主键(
- 引用完整性(参照完整性)- 关系中不允许引用不存在的实体
- 外键(
foreign key)
- 外键(
- 域(domain)完整性 - 数据是有效的
-
数据类型及长度
-
非空约束(
not null) -
默认值约束(
default) -
检查约束(
check)说明:在 MySQL 8.x 以前,检查约束并不起作用。
-
数据一致性(事务)
事务概述
事务是指满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。
一系列对数据库进行读/写的操作,这些操作要么全都成功,要么全都失败。
什么是 ACID?
ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必须要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。
- A Atomiccity 原子性
事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚;回滚可以用回滚日志来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可
- C Consistency 一致性
数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对同一个数据的读取结果都是相同的。
其主要特征是保护性和不变性 (Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是 100 元,那么五个账户总额是 500 元,如果在这个 5 个账户之间同时发生多个转账,无论并发多少个,比如在 A 与 B 账户之间转账 5 元,在 C 与 D 账户之间转账 10 元,在 B 与 E 之间转账 15 元,五个账户总额也应该还是 500 元,这就是保护性和不变性。
- I Isolation 隔离性
一个事务所做的修改在最终提交之前,对其他事务是不可见的;如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
- D Durability 持久性
- 一旦事务提交,则其所做的修改将会永远保存到数据库中,即使系统发生崩溃,事务执行的结果也不能丢失
- 系统发生崩溃可以用重做日志进行恢复,从而实现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。
MySQL 中的事务操作
- 开启事务环境
start transaction
- 提交事务
commit
- 回滚事务
rollback
- 查看事务隔离级别
show variables like 'transaction_isolation';
可以看出,MySQL 默认的事务隔离级别是
REPEATABLE-READ。
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
- 修改(当前会话)事务隔离级别
set session transaction isolation level read committed;
关系型数据库的事务是一个很大的话题,因为当存在多个并发事务访问数据时,就有可能出现三类读数据的问题(脏读、不可重复读、幻读)和两类更新数据的问题(第一类丢失更新、第二类丢失更新)。想了解这五类问题的,可以阅读 CSDN 网站上的 《Java面试题全集(上)》 一文的第 80 题。为了避免这些问题,关系型数据库底层是有对应的锁机制的,按锁定对象不同可以分为表级锁和行级锁,按并发事务锁定关系可以分为共享锁和独占锁。然而直接使用锁是非常麻烦的,为此数据库为用户提供了自动锁机制,只要用户指定适当的事务隔离级别,数据库就会通过分析 SQL 语句,然后为事务访问的资源加上合适的锁。此外,数据库还会维护这些锁通过各种手段提高系统的性能,这些对用户来说都是透明的。想了解 MySQL 事务和锁的细节知识,推荐大家阅读进阶读物 《高性能MySQL》,这也是数据库方面的经典书籍。
ANSI/ISO SQL 92 标准定义了 4 个等级的事务隔离级别,如下表所示。需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定到底使用哪种事务隔离级别,这个地方没有万能的原则。
索引
什么是索引?
索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。索引的实现通常使用 B 树或变种的 B+ 树。
索引的优缺点?
优点
- 通过创建索引,可以在查询的过程中,提高系统的性能
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
- 在使用分组和排序进行数据检索时,可以减少查询中分组和排序的时间
缺点
- 创建索引和维护索引要耗费时间,而且时间随着数据量的增加而增大
- 索引需要占用物理空间,如果要建立聚簇索引,所需要的空间会更大
- 在对表中的数据进行增加删除和修改时需要耗费较多的时间,因为索引也要动态地维护
数据库面试题
Sqlite 相关题
我有一个播放列表,可能有上万首歌,支持插入下一首,要求用数据库存储
如何设计这个模块?(2022 年 大宇无限)
- 索引,索引多了插入效率会降低
- 事务: 由于 Sqlite 的数据操作实质上是对于其数据文件的 IO 操作,频繁的插入数据会导致文件 IO 经常开闭,非常损耗性能能。事务作用便是使数据先缓存在系统中,提交事务时便提交所有的更改到数据文件,此时数据文件的 IO 只需要开闭一次,且避免了长期占用文件 IO 所导致性能低下的问题
- 预处理:预处理的原理就是将一条语句先预编译到数据库,下次再次执行相同的语句时,就不用再次编译,节省了大量的时间
- 内存模式