04 索引
索引的常见模型
哈希表、有序数组和搜索树。
哈希表这种结构适用于只有等值查询的场景
有序数组索引只适用于静态存储引擎
InnoDB 使用了 B+ 树索引模型,所以数据都是存储在B+ 树中的
B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数
基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。
主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小
05 索引
回到主键索引树搜索的过程,我们称为回表
避免回表的方法
- 覆盖索引-SELECT 主键
06 锁
MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类
表级锁
另一类表级的锁是 MDL(metadata lock)。
当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。
行锁
MyISAM 引擎就不支持行锁
在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
07 行锁
行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
所以一个事务中需要锁多个行,可以把冲突最多的锁往后放。
死锁
死锁出现后两种策略
- 等待超时 innodb_lock_wait_timeout
- 发起死锁检测。发现死锁后,主动回滚一个事务。
一般都是第二种,但是时间复杂度O(n) 消耗大量cpu
解决办法:
确保业务不会出现死锁
控制并发度-对于相同行的更新,在进去引擎之前排队。
或者从设计上优化-将一行改多行,减小一行的冲突,这样需要业务逻辑上详细设计。
08事务隔离
快照 mvcc如何工作
InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。
数据表中的一行记录,其实可能有多个版本 (row),每个版本有自己的 row trx_id。
不同版本之间通过 undo log(回滚日志)来计算得出。
每个事务或者语句有自己的一致性视图。普通查询语句是一致性读,一致性读会根据 row trx_id 和一致性视图确定数据版本的可见性。
更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。