零零散散看过许多关于MySQL的东西, 一直觉得不得要领, 最近看了一下MySQL技术内幕InnoDB存储引擎(第2版.姜承尧), 部分所得整理如下, 不成章法, 但求自己理解.
主键
每个表必须有主键, 可以是显示指定主键.
如果没有显示指定主键, 先查看是否有唯一非空的列, 如果有以该列为主键, 如果有多个唯一非空的列选择第一个(以索引定义的顺序为准, 不是以字段定义的顺序), 如果不存在唯一非空的列, 则自动生成主键 rowid 列 6字节宽
MVCC (Multi Version Concurrency Control)
MySQL以多版本并发控制(MVCC), 实现一致性非锁定读. 即如果读取的数据正在被delete或者update, 此时读取操作并不会等待该操作的完成, 而是直接读取该数据的快照. MVCC的实现依赖于undo log.
如果事物A把记录id=1的数据修改为id=2, 当事物未提交时, 事物B也把记录id=1的数据修改为id=3, 并且未提交; 然后, 事物A提交, 此时事物B再去查询记录id=1的数据
- 在 Read Repeatable 隔离级别下, 此时应该查询到B事物开始时的数据(改操作基于undo log实现, 故undo log除了进行事物回滚之外, 还有负责记录的历史版本的读取)
- 在Read Committed 隔离级别下, 此时应该查询到的数据为A提交之后(最新的快照)的数据, 由于A已经把记录的id改为了2, 此时事物B查的数据应为空
redo
MySQL 以 redo log 来保证数据的 持久化操作. redo log 分为两部分:
- 内存中的redo log 缓冲
- redo log 日志文件
缓冲中的redo log是易失的, MySQL以定期刷新缓冲到日志文件保证log不丢. redo 刷新策略可用参数 innodb_flush_log_at_trx_commit 控制,
- 当该参数为 0 时, 事物提交时不进行fsync(缓冲存盘)操作, 刷盘的操作仅在Master Threa中完成(每秒钟刷新一次,以sleep方式实现,可能有延时)
- 当该参数为 1 时 (默认为 1 ), 事物提交时进行一次fsync操作
- 当该参数为 2 时, 事物提交时, 将redo log 写入文件中, 但不fysnc(此时只能保证写入到操作系统的写缓冲中, 不会存入到硬盘上, 数据库发生宕机不会造成丢失, 但是操作系统宕机丢失)
undo
MySQL 以 undo log 来保证事物的回滚操作, 但是undo log不仅是作为回滚的依据(以上已经提到)
该日志是逻辑日志, 即该部分的操作是逻辑上与事物中的操作相反的操作, 可理解如下:
- 如果事物A insert 一条id=10的记录, 则undo log中记录一条 delete id = 1 的记录
- 同上理, 可推 delete 的操作也是一条对应的 insert操作
- 如果事物A更新一条记录为新的值, 则 undo log 记录一条更新改记录为原始值的记录
B+树索引
MySQL中的B+树索引可分为聚集索引(clustered index)与辅助索引(secondary index, 二级索引). B+树中的数据全都存在叶子节点上(所有的叶子节点是一个双向链表), 聚集索引叶子上存的是该索引对应的整行数据, 辅助索引存入的则是改数据的主键. 即聚集索引与辅助索引的区别是索引存储的是数据还是数据的主键.
需要注意的是: B+树索引并不能找到给定值的具体行, 只能找到数据所在的页, 然后数据库通过把页读入内存, 在内存中进行查找以得到要查找的数据.