范式
数据库三种范式如下。
范式 | 描述 | 反例 |
---|---|---|
第一范式 | 每个字段都是原子的,不能再分解 | 某个字段是JSON串,或者是数组 |
第二范式 | 1) 表必须有主键,可以是多个顺序属性的组合。2) 非主属性必须完全依赖主属性(这里指的是组合主键),而不能部分依赖。 | 好友关系表中,主键是关注人ID和被关注人ID,表中存储的姓名等字段只依赖主键中的一个属性,不完全依赖主键 |
第三范式 | 没有传递依赖(非主属性必须直接依赖主属性,不能间接依赖主属性) | 在员工表中,有部门ID和部门名称等,部门名称直接依赖于部门ID,而不是员工ID |
一般工程中,对于数据库的设计要求达到第三范式,但这不是一定要遵守的,所以在开发中,为了性能或便于开发,出现了很多违背范式的设计。如冗余字段、字段中存一个JSON串,分库分表之后数据多维度冗余存储、宽表等。
B+树
关于B树和B+树的概念,请见漫画算法:什么是 B+ 树?
B+树的逻辑结构
下面来看一下数据库中主键索引对应的B+树的逻辑结构。
该结构有几个关键特征(与一般的B+树有点不同)
- 在叶子节点一层,所有记录的主键从小到大的顺序排列,并且形成了一个双向链表,叶子节点的每一个Key指向一条记录。
- 在非叶子节点一层,每个非叶子节点都指向叶子节点中值最小的Key(但非叶子节点不存储记录),同层的非叶子节点也形成一个双向链表。
基于B+树的这几个特征,就可以很容易的实现范围查询、前缀匹配模糊查询、排序和分页(查询条件应是索引)。这里有几个要注意的问题。
- 模糊查询不应该使用后缀匹配或者中间匹配,因为索引的排序是按照从小到大排序的,只有前缀相同的才会被排列在一起,否则就用不上索引了,只能逐个遍历。
- 对于ofset这种特性,其实是用不到索引的。比如
select *** where *** limit 100, 10
,数据库需要遍历前面100条数据才知道offset=100的位置在哪。合理的分页方法就是不使用offset,把offset变成条件来查询。比如变成select *** where *** and id > 100 limit 10
,这样才能利用索引的遍历,快速定位id=100的位置。
事务与锁
事务的四大特性ACID。
- 原子性(A):事务要么不执行,要么完全执行。(如果执行到一半机器宕机了,已执行的部分需要回滚回去)。
- 一致性©:各种约束条件,比如主键不能为空,参照完整性等。
- 隔离性(I):只要事务不是串行的,就需要隔离(一般都是并行的,效率更高嘛)。
- 持久性(D):一旦事务提交了,数据不能丢失。