关系型数据库的优点
- 容易理解,因为它采用了关系模型来组织数据。
- 可以保持数据的一致性。
- 数据更新的开销比较小。
- 支持复杂查询(带 where 子句的查询)
非关系型数据库(NOSQL)的优点
- 无需经过 SQL 层的解析,读写效率高。
- 基于键值对,读写性能很高,易于扩展
- 可以支持多种类型数据的存储,如图片,文档等等。
- 扩展(可分为内存性数据库以及文档型数据库,比如 Redis,MongoDB,HBase 等,适合场景:数据量大高可用的日志系统/地理位置存储系统)。
索引:
- 类型:
- 主键索引:主键索引的叶子节点存的整行数据,在InnoDB里也被称为聚簇索引。
- 非主键索引:非主键索引叶子节点存的主键的值,在InnoDB里也被称为二级索引。
- 常见的底层数据结构:
- 三种常见的索引底层数据结构:分别是哈希表、有序数组和搜索树。
- 哈希表适用于等值查询的场景,不适合范围查询。
- 有序数组索引适用于静态存储引擎,等值和范围查询性能好,但更新数据成本高。
- N 叉树由于读写上的性能优点以及适配磁盘访问模式以及广泛应用在数据库引擎中。
- 三种常见的索引底层数据结构:分别是哈希表、有序数组和搜索树。
- 覆盖索引:
- 在某个查询里面,索引 k 已经“覆盖了”我们的查询需求,称为覆盖索引。
- 覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
- 索引下推:
- 在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数
- 索引失效:
- 左右模糊查询:节点是按字符串顺序排序的,左右模糊的话根本无法判断顺序,导致全盘扫描
- 函数表达式计算:数据库无法判断函数计算后的结果对应了哪些索引的值,只能全部计算一遍
- 隐式转换:很多情况数据库会帮你调用转换函数,导致编程了函数计算进而导致索引失效
- OR语句:只要有一个条件无法快速扫描就不行
- Change Buffer:
- 适用场景:多写少读 (在多读或立即读的情况下有反效果)
- 原理:数据库更新数据时会从磁盘读取数据,然后再进行修改,这样一来一回性能消耗极大,而ChangeBuffer技术可以将修改的数据先暂存到内存中,当数据库从磁盘读取内容时一并将待修改数据写入数据库中。相当于一个代办事项表的作用。
Redo Log:
对数据进行删改时,InnoDB先从磁盘找到数据,存进缓冲池中,然后对缓存值中的数据进行删改,将其变为脏页(指数据已被修改), 然后定时刷入磁盘 (类似数据库批量插入,提升性能,减少IO)
Redo Log会记录删改数据内容,在事务提交时刷入磁盘. 在脏页刷入磁盘时出意外时可以回放重做,保证数据持久性
Undo Log:
即回滚日志,记录逻辑日志,比如del操作就会记入相对的insert操作.用于保证原子性
快照读: 本质上用 实时性 换隔离性+可用性
数据在事务执行中可能会进行回滚,如果直接读在事务中的数据,万一事务回滚了,会导致脏读,也就是读到不存在的数据.为了防止这种情况就使用快照读的办法,可以防止脏读
并且可以做到同一条数据的读写不互斥,提高并发性能
延伸一下当前读:
快照读无法保证实时性,比如在高并发的情况下可能会导致读取的商品价格或者库存不实时,所以在商品 下单情况下需要强制使用当前读,来保证读取的价格或库存是最新的数据.
当前读需要给select语句上锁,所以他必须等待锁.
MVCC:
实现原理:
读视图:当前线程执行 快照读 时MVCC提供的数据依据,用于判断当前线程允不允许 读快照.读视图由当前线程创建
数据表字段会有至少两个隐藏字段:数据行的前任事务ID(trx_id)和前任undo Log指针ID,当执行快照读的时候会生成ReadView视图,记录四个字段: 1.当前活跃事务池 2.数据行最小事务ID 3.数据行预分配事务ID 4.数据行ReadView创建者的事务ID
解读:[事务ID是递增的]
1.前任事务ID==ReadView创建者事务ID => 代表当前申请快照的线程就是上任事务 ,允许读快照
2.前任事务ID < 最小事务ID => 代表上任事务已提交,数据已写入, 允许读快照
3.前任事务ID>预分配事务ID => 代表还没轮到上任事务,不允许读快照[几乎不可能出现]
4.最小事务ID< 前任事务ID<=预分配事务ID 并且前任事务ID不在活跃事务池中 => 代表上任事务是已提交的,允许读快照
tips:难点->
每一个线程都会带有事务ID,哪怕是读操作也需要事务,用于生成读视图 , 哪怕事务没提交也会写入前任事务ID
判断1:当前线程事务ID == 前任事务ID,例如线程select后修改前任事务ID为自己,又去做其他数据的update然后再回头select,就会触发这种判断.代表自己就是上任事务,不会发生回滚,允许快照读
判断2:当前线程想快照读,先读数据行的前任事务ID,再与活跃线程池的最小事务ID作比较,如果前任事务ID<最小事务ID,就代表前任事务已经结束提交,前任已经死了!不会复活回滚了!可以读快照
判断3:几乎不会发生,只是一个边界条件判断用来以防万一的,前任事务ID怎么会大于当前读视图的下一个事务ID呢
判断4:当前线程想读快照,先判断前任事务ID<=活跃事务池的最小事务ID,再确保前任事务ID不在活跃事务池
Undo Log版本链数据访问规则


