高性能MySQL

B+树索引

InnoDB使用的是B+树索引,内节点只有索引键、不存数据,叶节点除了索引键、还存记录的指针,所有叶节点顺序链接

注:wiki上关于B+树的图画成了B-树的图,中间节点的key应该是子节点中最小值(或最大值)

因为节点值基于键排序,适合最左前缀列查找、值范围查找

聚簇索引:像上述叶节点中这种索引键和记录指针放在一起的存储方式,叫做“聚簇”。存储着唯一一份全部记录的索引,叫做聚簇索引。一个表只能有一个聚簇索引。

二级索引:二级索引的叶节点中存着行的主键值(类似指针)。所以有两次B+树查找,第二次根据主键值去聚簇索引中查找对应的行,叫做“回表”。

覆盖索引:二级索引的叶节点中包含了查询所需的索引列数据,不再需要回表,索引覆盖了查询。

redo log(重做日志、事务日志)

redo log是存储引擎层的日志,是固定大小的循环写入文件,记录数据页的修改。当写入位置追一圈追上已落盘位置时,停止执行更新语句,将redo log落盘。

  • 把日志缓存写到日志文件,只把数据从应用程序缓存复制到内核写缓存。
  • 把日志文件落盘,才让操作系统把内核写缓存同步fsync()写到磁盘文件。

默认innodb_flush_log_at_trx_commit=1,事务提交时把redo log落盘,确保已提交事务不会丢失。

binlog(归档日志)

binlog是MySQL Server层的日志,是追加写入文件,记录数据更改的逻辑,用于主从复制。默认sync_binlog=0,写binlog不落盘;可让sync_binlog=1,每次提交都落盘。

redo log 的两阶段提交

为保证已提交事务的持久化,提交事务时先写redo log(未确认提交),再写binlog,然后redo log再确认提交。ref

有binlog才能提交:

  • 如果写binlog时奔溃,恢复时redo log回滚
  • 如果在redo log确认提交前奔溃,恢复时看对应事务的binlog是否存在,有则提交无则回滚

更新数据时的双写缓冲

把脏页面落盘到数据文件由后台线程进行,先写到双写缓冲文件,再写到数据文件。每个页面写两遍,可避免页面写不完整导致的数据损坏。

怎么知道页面完不完整?页面末尾都有校验值。如果不完整的页面写入双写缓冲,则原始页面依然在数据文件中,InnoDB恢复时就用原始页面替换双写缓冲中的损坏页面,相当于没写成功。如果双写缓冲写入成功,但数据文件写入失败,InnoDB恢复时就用双写缓冲中的页面替换数据文件中的损坏页面,相当于写入成功。

生成全局唯一ID

  • 两台服务器,一台生成奇数一台生成偶数
  • 一个全局节点生成自增数或批量分配数字
  • 使用分片号与自增数的复合值来做唯一ID

复制上的读写分离

参见复制滞后问题

在会话层,

  • 记录用户修改自己数据的时间,将该用户的查询在一段时间内指向主节点。用户不需要看到其他用户的最近更新,但需要看到自己的更新。
  • 记录主节点数据修改后的版本号(或时间戳、或日志偏移量)。如果从节点的数据太旧,就在主节点读取。顶层对象可以在下面任何对象有更新时增加版本号,这样只需检查一处就能判断更新。

写时复制的文件系统快照

LVM:GNU/Linux的逻辑卷管理

LVM快照在单个逻辑卷中的创建,只保留一个老版本。写时复制:创建快照时只简单标记快照创建时间,当数据变化时将受到影响的块复制到快照预留区域。