以下记录了我的一些数据库基础知识总结
数据库模型
层次模型:一颗有向树,每个节点有一个父节点,只有一个根节点。
网状模型:
关系模型:二维表
主键与外键
主键:能确定一条数据的唯一标识,主键只能有一个
外键:用来关联其他表保持数据一致性,可以有多个外键。
事务 ACID
A:原子性,事务是一个不可分割的工作单位,要么一起成功,或者一起失败
C:一致性,前后数据的完整性保持一致
I:隔离性,并发访问数据库,事务之间不会干扰
D:持久性,一旦一个事务提交,对数据库改变是永久性的,即使数据库发生故障也没有影响
事务隔离级别
第一类丢失更新:两个事务对同一数据更新,某条完成,另条异常终止,造成回滚,导致先完成的事务更新丢失。
第二类丢失更新:两条事务对同一数据更新,两条都成功,其中一条被覆盖。
脏读:事务 A 读取了事务 B 正在更新的数据,如果这时 B 进行回滚操作,A 读到的则是脏数据
不可重复读:A 多次读取数据,B 在读取过程中修改数据,导致 A 读到数据前后不一致
虚读(幻读):和不可重复读类似,不过是数据条数层面,两次读取的数据集合不同
隔离级别 | 脏读 | 不可重复读 | 虚读 | 丢失更新1 | 丢失更新2 |
---|---|---|---|---|---|
Read Uncommitted 读未提交 | 0 | 0 | 0 | x | 0 |
Read Committed 读已提交 | x | 0 | 0 | x | 0 |
Repeatable Read 可重复读 | x | x | 0 | x | x |
Serializable 可串行化 | x | x | x | x | x |
读未提交:高并发,但是很少实际使用
读已提交:大多数数据库默认隔离级别
可重复读:MySQL 默认隔离级别
可串行化:慢,通常不使用,可以采用其他机制解决如乐观锁、悲观锁
事务隔离级别设置只对当前链接有效,如一个 MySQL 命令窗口,相当于一个链接。
范式理论
第一范式:属性不可分割,即每个字段都应该不可再拆分。
第二范式:满足第一范式,数据库每一个实例(行)可以被唯一地区分
第三范式:满足第二范式,一个数据库表中不包含已在其他表中已包含的非主关键字信息。
视图
视图也称作虚表,是一组数据的逻辑表示,其本质是对应于一条 SELECT 语句,结果集被赋予一个名字,即视图名字。
逻辑上切割数据,减少数据存储冗余满足第三范式。
简单性:简化用户对数据的理解
安全性:授予视图用户权限,只能对给定的数据进行操作。
逻辑独立性:真实的数据表结构变化,不会带来影响只需修改视图
存储引擎
数据库存储引擎:是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以获得特定的功能。
MySQL 中可以针对不同表设置不同存储引擎。
常见的三种存储引擎:InnoDB、MyISAM、MEMPRY。
Innodb
InnoDB 是事务型数据库的首选引擎,InnoDB是目前MYSQL的默认事务型引擎。
支持事务安全表(ACID),支持行锁定,外键,崩溃修复能力,并发控制,自适应哈希索引。
MySQL 复制机制
异步复制:Master 执行后返回用户执行成功,Slave 读取 Master 日志进行异步复制
同步复制:Master 和 Slave 都执行后才返回用户执行成功。
半同步复制:Slave 不需要执行成功,只要日志成功接收,就可以通知 Master 从节点已同步(ACK)。
MySQL 读写分离
基于主从复制,Master 节点处理写操作,Slave 节点处理读操作。适用于读操作量大的场景减轻 Master 压力。
MYSQL Proxy
Proxy 直接从客户端接收请求,对 SQL 语句分析,判断操作类型然后分发至相应 mysql 服务器上。
Proxy 是一个中间件产品,可以实现读写分离、负载均衡、failover。
锁
前置内容
数据库并发三种场景:
读-读:没有问题,不需要并发控制
读-写:有隔离性问题,可能存在脏读、幻读、不可重复读
写-写:更新丢失问题,第一类更新丢失、第二类更新丢失
乐观锁、悲观锁是一种思想,而非具体实现,MVCC 是区别于乐观锁悲观锁的一种多版本并发控制。
悲观锁
悲观锁:默认数据被外界访问会发生冲突,所以整个数据处理过程都加锁,同一时间只有一个线程能访问数据。
通常数据库的悲观锁利用数据库本身提供的锁机制去实现。
悲观锁能解决,读-写
和 写-写
冲突。
实现
外界访问某条数据之前需要向数据库申请该数据的锁,如果成功则操作该数据加锁,失败则需要等待其他客户端释放锁。
优点与缺点
适合写多读少,能保证数据安全,但是性能相对较低。
乐观锁
乐观锁:默认外界的操作一般不会造成冲突,而是数据提交更新时,才会对数据冲突与否进行检测,如果发现冲突,则返回冲突信息,让用户决定如何做下一步。比如重试直到成功。
并不是利用数据库本身锁实现,可能利用某种实现逻辑做到乐观锁思想。
无锁方式去解决 写-写
冲突
实现
更改数据时,比较数据库内与更新版本的版本值或时间戳,如果提前了则说明数据发生冲突
- 使用数据版本(version)
- 使用时间戳(timestamp)
优点与缺点
适合读多写少的场景,如果写操作竞争激烈会导致开销比悲观锁高。
MVCC
一种并发控制方法,用更好的方式处理读写冲突,即使读写冲突时也能做到不加锁、非阻塞并发读。
当前读:是一种加锁操作。保证读取最新版本,会对读取数据加锁。
快照读:MVCC 的读操作。不加锁非阻塞读,前提隔离等级不是串行级别,串行级别会退化为当前读。快照读j基于多版本并发控制,可能不是最新数据。
总结
乐观锁悲观锁选择:
- 响应速度:需要快速响应,尤其是读多写少,可以使用乐观锁
- 冲突频率:冲突频率大,可以采用悲观锁
- 重试代价:重试代价大,可以采用悲观锁
MVCC 解决读写冲突,形成两种组合:
- MVCC + 悲观锁:MVCC 解决读写冲突,悲观锁解决写写冲突
- MVCC + 乐观锁:MVCC 解决读写冲突,乐观锁解决写写冲突
索引
索引是一个用于快速找到记录的数据结构。加速查询,但是写性能也会降低,还会占据一些磁盘空间。
查找时,先通过索引表找到该行数据对应的物理地址,然后直接访问该行数据。
几种索引
普通索引:没有限制
唯一索引:索引列的值必须唯一
组合唯一索引:列值组合必须唯一
Hash 索引和 B-Tree 索引
粗略看了 B树原理,-
是连接符,大致就是维护一个有序的多叉树,每个节点中有序的值做分隔符成为子节点的上下界。
B-Tree 索引支持最左前缀匹配,范围查询。
根据 B 树特性则限制有
- 如果不是按照索引的最左列开始查找,无法使用索引
- 如果查询中某列有范围查询,则右边列无法使用索引优化查询
Innodb 默认支持 B 树索引。
Hash 索引:冲突少时比较快,不支持范围查询,不支持部分查询,只存储哈希值和行指针。
innodb 有一个特殊功能『自适应哈希索引』,即发现某些索引值使用频繁则基于 B 树索引上在创建哈希索引。