MySQL InnoDB存储引擎要点
支持功能:
行级锁
四种锁:S(共享锁)、X(排他锁)、IS(意向共享锁)、IX(意向排他锁),前两种是行锁,后两种是表锁
意向锁是为了协调行锁和表锁的关系,加行锁前,必须先加相应意向锁,意向锁间相互兼容,意向锁和表锁有互斥关系
普通select不加锁,当前读select加共享锁,insert、update、delete加排他锁
三种行锁:Record Lock(记录锁),Gap Lock(间隙锁),Next-Key Lock(前两种结合)
行锁针对的是索引,唯一索引优化为Record,其他为Next-Key,注意死锁问题
事务
四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),隔离性通过MVCC和锁实现,原子性、持久性分别通过undo log(撤消日志)和redo log(重做日志)实现,一致性依赖前三者,由应用层保证满足约束条件。
通过redo log和undo log保证,前者写入文件,后者写入共享表空间,LSN(日志序列号)机制
存储结构:
表空间(tablespace)
共享表空间,存储undo信息、插入缓冲索引也、系统事务信息、两次写缓冲等
单独表空间(可选),存储数据、索引和插入缓冲Bitmap页
索引组织的,数据即索引,索引即数据,B+树结构
段(segment)
数据段
索引段
undo段
区(extent)
页(page)
数据页(B+ Tree Node)
undo页
系统页
事务数据页
插入缓冲位图页
插入缓冲空闲列表页
未压缩的二进制大对象页
压缩的二进制大对象页
行(row)
- 三个隐藏字段:隐藏的ID(可能)、6字节的事务ID(DB_TRX_ID)、 7字节的回滚指针(DB_ROLL_PTR)
实现上每个页对应一个B+ Tree Node,页大小和行大小决定了每个节点记录数
默认每个段4个区,每区64个页,每页16K,每行记录超出则行外存储至二进制大对象页
不考虑每页页头等数据,简化计算,非叶子节点每个条目至少包含一个8字节key和6字节指向子节点的指针,则每个非叶子节点最大可以有16K/14个条目;假设每条数据记录大小为1K,每个叶子节点页面可以存储16K/1K=16行数据记录;一个三层B+数最大可以存储(16K/14) x (16K/14) x (16K/1k) = 2191万行数据记录
缓冲池:
普通缓冲池
数据页
索引页
插入缓冲,辅助索引插入优化
自适应哈希索引,索引效率优化
锁信息
数据字典信息
重做日志缓冲池
额外缓冲池
- 缓冲池的数据结构本身、帧缓冲、缓冲控制对象等
两次写,LRU
索引 :
聚集索引
- key为索引值,value为行数据
辅助索引
- key为索引值,value为聚集索引键
采用B+树,非叶节点无数据,2到4层高度,减少磁盘IO次数
线程:
Master Thread
- 合并插入缓冲、脏页刷新(已单独)、undo页回收(已单独)等
IO Thread
- 读(页)线程、写(页)线程、插入缓冲线程、日志线程
Purge Thread
- undo页回收
Page Cleaner Thread
- 脏页刷新
MVCC:
事务以排他锁的形式修改原始数据
把修改前的数据存放于undo log,通过回滚指针与主数据关联,同时会记录下该行数据对应的创建版本号,即生成该数据行的事务ID
修改成功(commit)什么都不做,失败则恢复undo log中的数据(rollback)
查询操作时,拿到当前ReadView,即事务快照,是当前时间点系统内活跃的(未提交的)事务列表,对比要查询的数据最新及至历史版本,可得可见版本的数据行
InnoDB的操作可以分为当前读(current read)和快照读(snapshot read):
快照读(snapshot read)
- 普通select操作(不包括 select … for share, select … for update)
当前读(current read)
select … for share
select … for update
insert
update
delete
快照读是通过MVCC来实现的,视隔离级别不同,采用不同的ReadView生成策略
已提交读:每次读操作都会生成一个新的ReadView
可重复读:事务第一次进行读操作时才会生成一个ReadView
当前读是通过加锁来实现的,视隔离级别不同,采用不同的加锁策略
已提交读:写加Record排它锁,事务结束释放;读加Record共享锁,事务结束释放
可重复读:写加Next-Key排它锁,事务结束释放;读加Next-Key共享锁,事务结束释放
未提交读:无MVCC,无锁
可串行化:取消快照读,全为当前读
隔离级别不同,索引类型不同,加锁策略也不同
范围查询,RR下会加Gap Lock,非范围查询,唯一索引可只加Record Lock:
聚集索引:RC和RR,数据记录加Record Lock
唯一索引:RC和RR,索引记录和数据记录均加Record Lock
非唯一索引:RC,索引记录和数据记录加Record Lock;RR,索引记录加Record Lock + Gap Lock,数据记录加Record Lock
非索引:RC,所有数据记录加Record Lock;RR,所有数据记录加Record Lock + Gap LockLock;优化,不满足条件的记录释放锁