这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天
RDBMS 关系型数据库
事务Transaction:一组SQL语句组成的一个程序执行单元,需要满足ACID特性
- 原子性Atomicity:事务中的操作要么都发生,要么都不发生
- 一致性Consistency:事务不能破坏关系数据的完整性以及业务逻辑的一致性(状态必须合法)
- 隔离性Isolation:一个事务不能影响其他事务
- 持久性Durability:事务完成后,该事务对数据库的更改持久地保存在数据库中,不会因为宕机等问题丢失
高并发、高可靠、高可用
关系模型 所有的数据都是一张二维表(无论是实体,还是实体的联系)
每一行数据代表一个实体或者一个关系
一个关系型数据库系统的关键:
- SQL引擎:解决SQL执行问题
- 存储引擎:解决存储问题
- 事务引擎:解决事务ACID问题
SQL引擎
解析器Parser —— 词法分析、语法分析、语义分析
优化器Optimizer —— 基于规则的优化 / 基于代价的优化
为查询生成性能最优的执行计划
执行器Executor
将执行计划翻译成可执行的物理计划并驱动它执行
拆分成不同算子,一面对用户千变万化的SQL
- 火山模型:每个Operator调用Next操作,访问下一层Operator,获得下层Operator返回的一行数据,计算处理后返回给上层
优点:每个算子独立抽象实现,相互之间没有耦合,逻辑结构简单
缺点:每计算一条数据有多次函数调用开销(CPU效率不高) - 向量化:每次一批数据(Batch N 行) 函数调用次数1/N;CPU cache命中率更高;可以利用CPU的SIMD(single Instruction Multi Data)机制
- 编译执行:动态编译技术 编译成一个执行函数
存储引擎
如何存储数据?(是否可并发处理、是否可构建索引、行存列存或行列混合)
如何读写数据?(使用场景:读多写少 / 写多读少、点查场景、分析型场景)
- 管理内存数据结构
- 索引
- 内存数据
- 缓存(Query cache、Data cache、Index cache)
- 管理磁盘数据(磁盘数据的文件格式 & 增删改查)
- 封装读写算子(写入 / 读取逻辑)
In Memory 部分
Buffer Pool:数据缓存
把整个BufferPool分成各个Instance 降低页面访问的冲突
通过HashMap定位block
LRU算法实现淘汰机制
Log Buffer:用于写日志
On Disk 部分
系统表 存储元信息(描述数据库中的表和用户)
普通的表 存数据
Undo表
B+树构建索引
页面内页目录先通过二分法定位到对应槽,然后遍历该槽的分组中的记录找到指定记录
节点间双向链表连接以适合范围查询
一张数据表一般对应一颗或多颗树的存储,树的数量与建索引的数量有关,每个索引都会有一颗单独的树
聚簇索引和非聚簇索引: 主键索引也是聚簇索引,非主键索引都是非聚簇索引。除格式信息外,两种索引的非叶子节点都是只存索引数据的,比如索引为id,那非叶子节点就是存的id数据。 叶子节点的区别如下:
- 聚簇索引的叶子节点一般情况下存的是这条数据的所有字段信息。所以我们
select * from table where id = 1的时候,都是要去叶子节点拿数据的。 - 非聚簇索引的叶子节点存的是这条数据所对应的主键和索引列信息。比如这条非聚簇索引是username,然后表的主键是id,那该非聚簇索引的叶子节点存的就是 username 和 id,而不存其他字段。
相当于是先从非聚簇索引查到主键的值,再根据主键索引去查数据内容,一般情况下要查两次(除非索引覆盖),这也称之为回表 ,就有点类似于存了个指针,指向了数据存放的真实地址。
B+树的查询是从上往下一层层查询的,一般情况下我们认为B+树的高度保持在3层以内是比较好的,也就是上两层是索引,最后一层存数据,这样查表的时候只需要进行3次磁盘IO就可以了(实际上会少一次,因为根节点会常驻内存),且能够存放的数据量也比较可观
在Innodb的B+树中,我们常说的节点被称之为 页(page)。页 是InnoDB存储引擎管理数据库的最小磁盘单位,我们常说每个节点16KB,其实就是指每页的大小为16KB。每个页当中存储了用户数据,所有的页合在一起组成了一颗B+树
若有联合索引(A,B) 查询条件中如果没有A的支持,B的索引是散列的、不是连续的,不会走索引