文章目录
7.1 数据库的基本概念及原则
7.1.1 存储引擎
1. MyISAM
- MySQL 5.1以及之前的版本的默认存储引擎
- 表级锁,不支持事务、外键、行级锁
- B+树的非聚簇索引
2. InnoDB
- MySQL的默认存储引擎
- 事务(Transaction)、外键(foreign keys)、行级锁(row-level locking)
- 自增(auto_increment)
- 回滚(Rollback)
- 事务安全(Transaction-safe)
- 崩溃修复能力(Crash Recovery Capabilities)
- 多版本并发控制(Multi-versioned Concurrency Control)
- B+树的聚簇索引
3. TokuDB
- 支持事务
- 分形树(Fractal Tree)的聚簇索引
分形树的结构与B+树有些类似,只是在分形树中,子节点带一个Message Buffer,这个Message Buffer是一个先进先出队列,用来缓存更新操作,具体的数据结构如图所示。这样,每一次插入操作都只需落在某节点的Message Buffer上,就可以马上返回,并不需要搜索到叶子节点。这些缓存的更新操作会在后台异步合并并更新到对应的节点上。
TokuDB在线添加索引,不影响读写操作,有非常高的写入性能,主要适用于要求写入速度快、访问频率不高的数据或历史数据归档。
4. Memory
- 数据存于内存,访问速度快,断电容易丢失。每个表对应一个磁盘文件用于持久化。
- 支持散列(Hash)索引、B树索引。散列索引对于单个数据的查询效率特别高;B树索引对于某个范围的数据可以使用部分查询、通配查询、不等于、小于等于、大于等于等操作。
7.1.2 创建索引的原则
B+树索引的聚簇与非聚簇
- 根据主键查找时,聚簇索引较快(叶子节点存放数据),非聚簇索引较慢(叶子节点不存数据);
- 根据非主键查找时,聚簇索引较慢(查找2个索引:非主键索引->主键索引),非聚簇索引较快(查找1个索引:非主键索引);
- 数据发生移动时,聚簇索引维护成本低(仅更新主键索引),非聚簇索引维护成本高(更新所有索引)。
索引的种类
单列索引(主键索引、普通索引、唯一索引)、多列索引、全文索引
创建索引的原则
◎ 选择唯一性索引:唯一性索引一般基于Hash算法实现,可以快速、唯一地定位某条数据。
◎ 为经常需要排序、分组和联合操作的字段建立索引。
◎ 为常作为查询条件的字段建立索引。
◎ 限制索引的数量:索引越多,数据更新表越慢,因为在数据更新时会不断计算和添加索引。
◎ 尽量使用数据量少的索引:如果索引的值很长,则占用的磁盘变大,查询速度会受到影响。
◎ 尽量使用前缀来索引:如果索引字段的值过长,则不但影响索引的大小,而且会降低索引的执行效率,这时需要使用字段的部分前缀来作为索引。
◎ 删除不再使用或者很少使用的索引。
◎ 尽量选择区分度高的列作为索引:区分度表示字段值不重复的比例。
◎ 索引列不能参与计算:带函数的查询不建议参与索引。
◎ 尽量扩展现有索引:联合索引的查询效率比多个独立索引高。
索引失效的情况
- null值条件(is null,is not null)
- 非运算条件(<>,!=,not in,not exist)
- like前置%条件(like ‘%小%’,like ‘%小明’)
- 函数条件(round(score))
- 算术运算条件(+,-,*,/)
- 数据类型的隐式转换
- 联合索引的前导列不作为查询条件
7.1.3 数据库三范式
范式是具有最小冗余的表结构。
1.第一范式:列不可再分。
如果每列都是不可再分的最小数据单元(也叫作最小的原子单元),则满足第一范式,第一范式的目标是确保每列的原子性。
2.第二范式:列不能对联合主键存在部分依赖。
第二范式在第一范式的基础上,规定表中的非主键列不存在对主键的部分依赖,即第二范式要求每个表只描述一件事情。
3.第三范式:列不能对主键存在依赖传递。
第三范式的定义为:满足第一范式和第二范式,并且表中的列不存在对非主键列的传递依赖。
7.1.4 数据库事务
事务的特性:原子性、一致性、隔离性、持久性。
7.1.5 存储过程
存储过程指一组用于完成特定功能的SQL语句集,它被存储在数据库中,经过第一次编译后再次调用时不需要被再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
存储过程的优化:
- 尽量利用一些SQL语句代替一些小循环,例如聚合函数、求平均函数等。
- 中间结果被存放于临时表中,并加索引。
- 少使用游标(Cursors):SQL 是种集合语言,对于集合运算有较高的性能,而游标是过程运算。比如,对一个 50 万行的数据进行查询时,如果使用游标,则需要对表执行50万次读取请求,将占用大量的数据库资源,影响数据库的性能。
- 事务越短越好:SQL Server支持并发操作,如果事务过长或者隔离级别过高,则都会造成并发操作的阻塞、死锁,导致查询速度极慢、CPU占用率高等。
- 使用try-catch处理异常。
- 尽量不要将查找语句放在循环中,防止出现过度消耗系统资源的情况。
7.2 数据库的并发操作和锁
7.2.1 数据库的并发策略
乐观锁(版本号、时间戳)、悲观锁
7.2.2 数据库锁
1.行级锁
行级锁对某行加锁,是一种排他锁,在执行以下数据库操作时,数据库会自动应用行级锁:
- INSERT
- DELETE
- UPDATE
- SELECT … FOR UPDATE [OF columns] [WAIT n|NOWAIT]
2.表级锁
表级锁对某张表加锁。
3.页级锁
页级锁的锁定粒度介于行级锁和表级锁之间。表级锁的加锁速度快,但冲突多;行级锁冲突少,但加锁速度慢。页级锁在二者之间做了平衡,一次锁定一页记录。
4.基于Redis的分布式锁
使用场景:分布式业务系统、分布式数据库。
Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。设置成功,返回 1 。 设置失败,返回 0 。
7.2.3 数据库分表
- 垂直切分:将表按照功能模块、关系密切程度划分,并部署到不同的库中。
- 水平切分:在一个表中的数据量过大时,我们可以把该表的数据按照某种规则进行划分,然后部署到不同的库中。
7.3 数据库分布式事务
7.3.1 CAP理论与BASE理论
CAP理论
CAP理论指的是在一个分布式系统中,分区容错性客观存在的前提下,强一致性与可用性不能同时满足。
- 分区容错性(Partition tolerance):系统如果不能在时限内达成数据的一致性,意味着发生了分区,就必须在C和A 之间做出选择。
- 可用性(Availability):在集群中一部分节点发生故障后,集群整体能否响应客户端的读写请求。
- 一致性(Consistency):在分布式系统的所有数据备份中,在同一时刻是否有同样的值。一致性可分为:强一致性(从节点全部同步)、弱一致性(从节点部分同步部分异步)、最终一致性(从节点全部异步)。
BASE理论
BASE理论是CAP理论的延伸,包括基本可用(Basically Available)、柔性状态(Soft State)、最终一致性(Eventual Consistency)三个原则:
- 基本可用(BasicallyAvailable):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。
- 软状态(SoftState):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。
- 最终一致性(EventualConsistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。
7.3.2 二段提交协议2PC
Prepare(准备阶段)、Commit(提交阶段)。
两阶段提交的缺点
- 协调者单点故障。
- 接收到消息的参与者与协调者一起宕机,新协调者无法确定该参与者的事务的最终状态。
- 同步阻塞问题:参与者的任务是阻塞执行的。
- 数据不一致:在二段提交的第2 阶段,在协调者向参与者发送Commit(提交)请求后发生了故障或网络异常,导致只有一部分参与者接收到Commit请求,于是整个分布式系统出现了数据不一致的现象,这也被称为脑裂。
7.3.3 三段提交协议3PC
CanCommit、PreCommit、DoCommit。
对二段提交的改进:
- 在第1 阶段和第2 阶段都加入一个预准备阶段,以保证在最后的任务提交之前各参与节点的状态是一致的。
- 引入超时机制:在协调者和参与者中引入超时机制,参与者超时时协调者认为参与者执行失败,协调者超时时参与者自动进行提交阶段。
解决问题:
- 超时机制,超时时参与者自动进行提交阶段,解决协调者单点故障问题;
- 预提交阶段,参与者事务转换成统一的状态,解决某个参与者与协调者一起宕机,新协调者无法确定该参与者的事务的最终状态的问题。
7.3.4 分布式事务
二段提交型事务(对业务无侵入)
对2PC的实现,有JTA/JTS(Java对2PC的实现,仅适用于单体应用下的分布式数据库)和XA(数据库对2PC的实现)。
补偿型事务(TCC型)(对业务有侵入)
TCC指的是Try - Confirm - Cancel:
- Try:预留,即资源的预留和锁定。
- Confirm:确认,执行业务。
- Cancel:撤销,撤销对资源的预留和锁定。
注意问题:空回滚、悬挂、幂等性。
异步确保型事务
RocketMQ 提供了事务消息的功能,我们只需要定义好事务反查接口即可。
最大努力通知型事务
当半消息被commit了之后确实就是普通消息了,如果订阅者一直不消费或者消费不了则会一直重试,重试N次后进入死信队列。
最大努力型通知事务通过消息服务使分布式事务异步解耦,并且模块简单、高效,但是牺牲了数据的一致性,在金融等对事务要求高的业务中不建议使用,但在日志记录类等对数据一致性要求不是很高的应用上执行效率很高。
7.4.5 Seata支持的4种模式
XA模式(无侵入)
对2PC的实现,分3种角色:事务管理器、事务协调器、资源管理器
流程:
1.事务管理器创建一个全局事务并生成一个全局唯一的 XID,交给事务协调器管理;
2.资源管理器向事务协调器注册分支事务,纳入 XID 的管辖;
3.事务管理器向事务协调器发起针对 XID 的全局提交或回滚决议;
4.事务协调器调度 XID 管辖下的全部分支事务完成提交或回滚请求。
AT模式(无侵入)
用户处理第一阶段:单体事务
Seata实现第二阶段:保存更新前的数据副本、更新后的数据副本,但倘若在回滚时实时数据与更新后的数据副本不一致,则需要人工处理。
TCC模式(有侵入、多个短事务)
注意问题:空回滚、悬挂、幂等。
Saga模式(有侵入、长事务)
注意问题:空回滚、悬挂、幂等。