这次学习的课程是面向面试的, 所以很多知识都是根据面试中出现的高频问题来学习的.
如何构建一个数据库
这个是一个很空泛很大的问题, 但是我们可以将数据库的构建和一个软件的构建进行类比 :
- 首先需要硬件存储模块, 比如 : 机械硬盘, 固态硬盘等来存储数据;
- 数据库程序实例 : 数据仅仅存储起来是没有任何意义的, 需要对数据库中的数据进行操作, 比如增删改查, 这个就需要数据库程序实例来完成这件事情;
- SQL 解析 : 需要将 SQL 语言解析, 从而调用程序实例;
- 缓存机制 : 因为数据库的操作时间大部分是用于 I/O 操作, 所以可以将经常使用的数据缓存起来, 减少 I/O 的访问时间
- 日志管理 : 采集数据库的相关信息
- 权限划分 : 不同级别的操作者拥有不同级别的权限
- 索引管理 : 优化数据库操作数据的时间
- 锁管理 : 保证并发操作时数据的正确性
以上是一个基本的数据库应该包含的一些功能, 接下来进一步对数据库的常见问题与知识进行总结.
索引相关问题
为什么需要索引
因为不使用索引的话, 需要对数据库进行全局遍历搜索, 当数据量大的情况下, 这样的全局遍历操作耗费的时间太大. 使用索引是对数据库查找操作的优化.
什么样的信息可以成为一个索引
主键、唯一键以及普通键
哪些数据结构可以作为索引, 其特点是什么
- 二叉查找树
二叉查找树可以作为索引, 但是树的高度太大, 导致 I/O 操作次数太多, 尤其是在该树的每一个非叶子结点只有右子树或者只有左子树的情况下, I/O 的次数过大. - B 树
因为二叉查找树的 I/O 次数过大, 其原因在于, 二叉查找树每个结点最多只有 2 个子树, 所以导致二叉查找树的层数太高, 而 B 树就解决了这个问题, 平衡多路查找树 - B+ 树
B+ 树是 B 树的一种变形, 后面深入讨论两者的差别 - 哈希
哈希建立索引的话, 每一个数据都要对应一个索引, 因为哈希索引不满足排序, 所以不能使用范围查询
B 树和 B+ 树的定义与区别, 为什么通常选择 B+ 树而不是 B 树作索引的数据结构
B 树的定义 : 如果树的每个存储快最多有 m 个孩子, 那么这样的树就是 m 阶 B 树.
- 根结点至少包括 2 个孩子
- 树中每个结点最多含有 m 个孩子 ( m >= 2 )
- 除根结点和叶结点外, 其他每个结点至少有 ceil(m/2) 个孩子 (ceil 函数表示取上限)
- 所有叶节点都位于同一层
- 假设每个非终端结点中包含有 n 个关键字信息, 其中
- Ki( i = 1...n) 为关键字, 且关键字按顺序升序排序 K(i - 1) < Ki
- 非叶结点的关键字数量小于其指针数量
- 非叶节点的指针 : P[1], P[2],...P[M]; 其中 P[1] 指向关键字小于 K[1] 的子树, P[M] 指向 关键字大于 K[M - 1] 的子树, 其他 P[i] 指向关键字属于 (K[i - 1], K[i]) 的子树
B+ 树的定义与 B 树的定义基本相同, 除了 :
- 非叶结点的子树结点和关键字的个数相同
- 非叶结点的子树指针 P[i] 指向关键字 [ K[i], K[i + 1] ] 的子树
- 非叶结点仅用来作索引, 数据都保持在叶子结点中
- 所有叶子结点均有一个链表指针指向下一个叶子结点
从上面的定义可以看出, B 树索引可能不需要遍历到叶子结点就找到了关键字, 而 B+ 树索引必须遍历到叶子结点; 对于范围查找, B 树需要重复地中序遍历, 而 B+ 树只需要利用叶子结点的链表指针进行遍历即可. B+ 树的非叶子结点不存放关键字的具体信息, 只存放指针信息, 这样每次读入内存的索引信息就更多, 从而降低了 I/O 的次数.
B 树中, 任何一个关键字出现且仅出现在一个结点中, 而 B+ 树中, 同一个数字可能在不同结点中重复出现. 通常 B+ 树上有两个头结点, 一个指向根结点, 一个指向关键字最小的叶子结点. 根结点的最大元素就是 B+ 树的最大元素.
MyISAM 与 InnoDB 的区别是什么
MyISAM 默认支持表级锁, 不支持行级锁; 同时 MyISAM 不支持事务
InnoDB 默认支持行级锁, InnoDB 支持事务. InnoDB 在没有用到索引的时候, 使用的是表级锁, 用到索引的情况下, 使用的是行级锁.
数据库事务的四大特征
ACID :
- Atomic : 原子性, 事务的操作是原子性的, 要么执行, 要么不执行
- Consistency : 数据库在事务执行的前后状态保持一致
- Isolation : 一个事务的执行过程, 对于另一个事务是不可见的
- Durability : 事务的执行结果是持久性的.
事务隔离级别及解决的并发问题
- read-uncommitted : 一个事务对数据库的修改在未提交之前, 对另一个事务也是可见的. 解决了更新丢失的问题
- read-committed : 一个事务对数据库的修改在未提交之前, 对另一个事务是不可见的. 解决了脏读的问题
- repeatable-read : 在读取数据时, 不再允许修改操作. 解决了不可重复读的问题
- seriable : 事务序列化执行. 解决了幻读的问题.