数据库
事务特性
ACID:原子性、隔离性、一致性、持久性
一致性:执行事务前后,数据保持一致。多个事务对同一数据读取一致。
范式
- 每个列不可再拆分
- 非主键列完全依赖于主键,不能只依赖于主键的一部分
- 非主键列只依赖于主键,不依赖于其它键
隔离级别
MySQL默认隔离级别:可重复读
隔离级别 | 一句话解释 | 锁 | 问题 |
---|---|---|---|
未提交读 read uncommited | A 事务可读到 B 事务未提交的数据 | 读数据时未加锁 写数据时只加行级共享锁 | 脏读,读到另一个事务未提交的数据 |
提交读 read commited | 一个事务要等另一个事务提交后才能读到数据 | 读数据时加行级共享锁 写数据时加行级排他锁,写完立即释放 | 不可重复读,事务结束前读取了另一个事务已提交的更新数据 |
可重复读 | A 事务读取数据时,不允许 B 事务修改操作 | 读数据时加行级共享锁,直到事务结束 写数据时加行级排他锁,直到事务结束 | 幻读,事务结束前读取了另一个事务已提交的新增数据 |
序列化 | 串行化顺序读取 | 表级共享锁,直到事务结束 表级排他锁,直到事务结束 | 无 |
悲观锁和乐观锁
行级表级的写锁(排它锁)即为悲观锁
MVCC 多版本并发控制 Multiversion Concurrency Control
乐观锁实现方案之一:通过增加版本号(事务ID),来解决数据不可重复读的问题
insert逻辑:
创建一条记录,DB_TRX_ID为当前事务ID,DB_ROLL_PTR为NULL。
delete逻辑:
将当前行的DB_TRX_ID设置为当前事务ID,DELELE_BIT设置为1。
update逻辑:
复制一行,新行的DB_TRX_ID为当前事务ID,DB_ROLL_PTR指向上个版本的记录,事务提交后DB_ROLL_PTR设置为NULL。
SELECT逻辑:
1、只查找创建早于当前事务ID的记录,确保当前事务读取到的行都是事务之前就已经存在的,或者是由当前事务创建或修改的;
2、行的DELETE BIT为1时,查找删除晚于当前事务ID的记录,确保当前事务开始之前,行没有被删除。
索引数据结构
- 采用B+树,innodb引擎。数据与索引为同一个文件,叶子结点即数据块,叶子结点未尾有指针相互串联
- 辅助索引(主键外其它列的索引)非叶子节点存储该列的值,叶子节点(数据块)存储主键值。所以辅助索引需要查询两遍
- 优点:
- 树的深度低,磁盘IO次数少,因而效率更高
- 查询效率更稳定,因为数据都放在最后
聚簇索引
特点:
- 索引与数据在一块,找到索引后即找到数据,无需再次查找
- 索引顺序与数据块的磁盘顺序相同,所以一个表只能有一个聚簇索引
- 主键都是聚簇索引,非主键索引都是非聚簇索引
非聚簇索引
- 索引与数据不在一块,索引存储着数据的指针,需要再再次查找
undo、redo、binlog
undo、redo:事务用,记录是物理操作,重复执行没有问题
binlog:主从同步用,记录的是逻辑操作,即SQL语句,重复执行数据会出问题
引擎:MyIsam 和 innodb
- innodb 支持事务、外键、行级锁,MyIsam不支持
- innodb 主键索引与数据在同一个文件中,MyIsam索引与文件是分开的
优化
思路:
- 确认瓶颈,优化瓶颈处
- 添加业务日志,查看是否业务问题
- 配置慢查询日志,收集所有的慢SQL
- 优化业务逻辑,优化SQL
- 比如将联表拆成业务代码来做
- 分析慢SQL:
- 没有索引,添加索引
- 有索引,通过 explain 命令分析是否用到了索引,根据一堆索引失效常见问题去优化。比如联合索引最左匹配,like查询没用上索引,查询时字段上加了函数等等
- 降低select量,降低非聚簇索引二次查询,或者传输量
- 仍然慢,加缓存
- 数据库读写分离
- 加机器
- 分库分表
分库分表
垂直分
即切分字段,将不常用的字段新建表来存
水平分
即切分数据
问题
JOIN、事务、自增ID会出现问题
方案
- range
- 即按范围,比如按id范围,按时间范围
- 冷热分离,不均衡
- hash
- 比如按ID取模
- 均衡,但不方便扩容
- 雪花算法:分布式唯一ID的解决方案
- 时间 + 机器ID + 流水号
- 方便扩容
- 一致性hash算法
- 数据被映射到一个232 的环上
- 机器节点也被映射到一个232 的环上
- 按顺时针方向分发数据到下一个最近的机器节点
- 不均衡时可使用虚拟节点,再加一层映射
- 方便扩容,只影响环上逆时针方向的前一个节点而已
分页查询
说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。
正例:先快速定位需要获取的id段,然后再关联:
SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
Null
null本身是用特殊方式表示的,会占用字节
char、varchar
- char存储时会忽略后面空格
- 超长均会截断
- varchar会多一个或两个字节来存储实际长度
- char不管实际多少字符,均占用最长字节
## 分布式事务
参考文章:分布式事务
CAP:
- C:Consistency 一致性:同一数据的多个副本是否实时相同。
- A:Availability 可用性:一定时间内 & 系统返回一个明确的结果 则称为该系统可用。
- P:Partition tolerance 分区容错性。将同一服务分布在多个系统中,从而保证某一个系统宕机,仍然有其他系统提供相同的服务。
BASE:
- BA:base availabe 基本可用
- S:soft State。数据不用实时一致
- E:Eventual Consisstency:但数据经过一段时间后最终是一致的
基于可靠消息服务的分布式事务
全部成功时:
- 发起方及事务方A、消息中心 M、协助方B
- A发送给M,要求B执行一段事务
- M收到后,入库,返回给A已收到
- A执行自己事务,完毕后向M发送commit。发送完毕后A即结束,进行其它处理
- M同步发送要求B执行事务的代码给B,并进行重试确保事务完成
A事务执行失败时:
- 发起方及事务方A、消息中心 M、协助方B
- A发送给M,要求B执行一段事务
- M收到后,入库,返回给A已收到
- A执行自己事务,执行失败,向M发送rollback。发送完毕后A即结束,进行其它处理
- M撤销自己的消息
M未收到commit消息时:
- 发起方及事务方A、消息中心 M、协助方B
- A发送给M,要求B执行一段事务
- M收到后,入库,返回给A已收到
- A执行自己事务,执行失败,向M发送rollback/commit,但消息丢了。发送完毕后A即结束,进行其它处理
- M一段时间后回查A状态,commit即提交,rollback即回滚,处理中则继续等待
发布于 2020/08/20
浏览
次