画布 1
InnoDB
  线程
    Master Thread
      这是性能抖动的一个主要源泉
      refresh dirty page（大致上可以被认为是 check point）
        比较灵活，允许调配
        sharp checkpoint
          刷新所有脏页
        fuzzy checkpoint
          刷新部分脏页
          Master Thread Checkpoint
            定时刷新
          FLUSH_LRU_LIST Checkpoint
            LRU list 中始终要有100个空白页，空白页不够的时候必定会触发made young，如果被淘汰的是脏页，又会触发 checkpoint。
          Async/Sync Flush Checkpoint
            在 flush list里选取脏页刷回磁盘
            check point age = redo_lsn - checkpoint_lsn
              这个东西的差值意味着延迟很高了，不处理就会有水位堆积的问题，所有的生产位点和消费位点的设计都允许我们观测延迟，这是一种通用的编程思想
              旧版本的 InnoDB 允许这个值相对于内存保持在一定比例里，但大内存遗留的 checkpoint 会导致恢复时间过久
合不合理要看它和 log group capacity的差异
            log sequence number 单调递增
            async_water_mark < checkpoint_age<sync_warter_mark
          Dirty Page too much Checkpoint
            innodb_max_dirty_page_pct 通常为 75
            为了保证有足够多的页可用
      不断把 redo log 从 buffer 写入磁盘中
      merging insert buffer
        merge 意味着从 table space 里读取数据页，并把物理页和内存页做合并，再写回table space
      recycle undo page
      四大 loop
        loop 主循环
          循环总有睡眠
          睡眠总会带来不确定的延迟
        background loop
        flush loop
        suspend loop
    IO Thread
      insert buffer thread
      read thread
      write thread
      log thread
    Purge Thread
      专门回收 undo page，线程数越多，undo 页的回收越快
        删除 undo 页的不要的 undo log
        删除被 is_deleted 的记录，这些事务在被提交时不能直接删除的原因是为了支持其他事务继续 MVCC 地快照读，可以作为 read view 的基础
    page cleaner thread
      这个线程的出现是为了保证阻塞性的脏页操作不会阻塞用户线程性能
  内存
    管理线程和进程的数据结构
    buffer pool
      innodb_additional_mem_pool_size
      redo log buffer
        通常为8mb
        打开双1写入则 redo log buffer 会失效（只有秒杀场景可以容忍这种行为）
        三种方式会导致 redo log 的提交
          日志会先写入这个内存区域，然后被 master thread 通过主循环写入 redo log 文件
          事务提交会导致，redo log buffer 被提交
            事关事务的执行，这里没有任何惰性策略
          redo log 的水位超过1/2时会导致 redolog 刷新（水位刷新法）
      innodb_buffer_pool
        data page（这个名字可以在沈剑那里看到，MySQL 官方文档也大量使用 page 这个词）
        index page（这个名字可以在沈剑那里看到，MySQL 官方文档也大量使用 page 这个词）
        insert buffer
        adaptive hash index
        lock info
        data dictionary
        占了绝大部分缓冲池的容量
        这三者特别重要
      工作模式
        从磁盘上读取一页，把它 FIX 在 buffer pool 里
        查询时若命中，则直接读取此页
        对页进行修改，则先修改 buffer pool 里的页，然后依靠 checkpoint 的机制把修改刷回磁盘上
          这一页可以这样修改，所以唯一的主键索引自己也有自己的 change buffer 的，就是 buffer pool 的数据页本身了
      instances 数量
        高版本的 MySQL 允许不同的页大小放在不同的 buffer pool 实例里
      管理模式
        一般的 mem pool 有两种管理模式，bit map 和 linked list 模式
          不同标记的列表，管理打了不同标记的列
          LRU List
            16KB page
            2 如果 free list 里面没有页了，从 LRU 的old list 里淘汰队尾页，放到 new list 里，这个过程被称为 made young。made young 可以在 innodb status 里像 gc log 一样被阅读出来
          Free List
          FLush List
  其他关键特性
    引入 Delete Buffer 和 Purge Buffer，升级为 Change Buffer
    引入双写缓冲区可以解决部分写失效的问题（partial page write），提高了数据页的可靠性
    Insert Buffer
      为了加快对非唯一辅助索引的插入性能存在
        因为每个表里通常都有大量的辅助索引，这些索引通常也是非唯一的，所以这个 buffer 经常要被用到。
反观唯一索引（不管是不是辅助索引）的缺点就是，无法利用插入缓冲，插入性能不高。
唯一索引的读必定触发 merge，这样buffer就无意义了。
        change buffer 是为了让修改只buffer 在内存里而减少一次磁盘io（交给其他异步的操作如 master线程去做），如果写后直接读，这个磁盘io还是必不可少，不 merge 则，其实浪费了 change buffer。
      同时存在 buffer pool 和物理页里，内部实现是一棵跨越所有表的 B+ 树
      步骤
        先确认能不能直接改 buffer pool LRU 列表里的页
        如果没有则在insert buffer 里面创建特殊记录
        过一会再触发合并（所谓的merge，就是 apply operation to page）
      merge Insert/Change Buffer
        辅助索引页被读取到 buffer pool 时，如同 LSM tree 一样，读取相关数据一定会触发一次 merge。
注意，任何的读写操作都会触发 index page 和 data page 进入 buffer pool，这是不可避免的。
根据 MySQL 的官方文档，这一步的merge 是发生在 buffer pool 里的，不是 disk 上。mem 和disk 的一致性问题由 redo log 和 checkpoint 机制保证。
        insert buffer bitmap 显示，（内存里）辅助索引页已没有空间时，会触发 merge
        master thread 定期执行 merge
    double write
      先建立一个 2mb 的内存里的 double write buffer，然后在 disk 上建立两个连续的1mb的共享表空间
      每次写入table space 的若干脏页本身可以是随机分布在真正的table space 里的，但都会先写入 double write buffer 的内存部分
      将 double write buffer 的内存部分的内容分两次写入整个double buffer 的连续共享表空间，可以被看作 first write
      第一个共享表空间写完后，直接从 double write buffer 的内存部分 fsync 到磁盘上，这时候是随机写
      double write buffer 存在的意义是，部分写失效发生时，可以通过完整和连续的共享表空间做页恢复（recover）
    adaptive hash index
      基于统计
      只能优化等值查询
      innodb_adaptive_hash_index
    async io
      支持对多路 io 的优化
    flush neighbor page
      刷新一个 extent 的页
      针对机械硬盘有用，在 SSD 硬盘下可能需要关闭这个选项
    为 InnoDB 提供了性能提升，类似 LSM-Tree支持随机写
  文件
    表空间 table space
      extent
        page
    参数文件
      mysql --help | grep my.cnf
      编译时内置一些参数，找不到配置文件也能启动。
Oracle 不行
      参数类型
        dynamic
        static
        global
          会在instance 当前生命周期里生效，不会 sync 到配置文件里
          不会修改已生效 session 的配置
        session
    日志文件
      error log
      slow log
        执行时间超过一定阈值的 statement（或者 query）
        没有使用 index 的statement
      bin log
        用途
          我错失的恢复方法
          point-in-time recovery = backup + binlog
          audit
          replication
        配置
          配置项
            sync_binlog=1
              不这样，binlog 无法刷盘
            innodb_support_xa=1
              因为 redo log 和binlog是二段式提交的，不这样commit 没提交，binlog 也无法回滚。这个配置是为了保证 binlog 和 redo log 内容的一致性
              第三个1，保证两段式提交的一致性
          写入或忽略某个库的日志
            这可以控制同步的数据量
          二重 slave 要单独配置
            所以 MySQL 可以在binlog 配置或者打标的方法防止数据回环
        解读
          mysqlbinlog --vv --start-position=1065 test.000004 可以可视化地解读 row 格式的binlog
        逻辑日志-注意，STAMENTMENT、ROW和 MIXED 都是逻辑日志
        只在数据库提交那一刻一次性写入，类似 dump
      redo log
        物理日志-操作数据页
        只有 InnoDB 的事务信息
        innodb_flush_log_at_trx_commit=1
          预防数据库实例宕机
          预防操作系统宕机
          log buffer -> log file
          只要这两者并不同时宕机，发生灾害时事务信息不会丢失
        事务流程中持续并发写入写入
        有 51 种 redo log type
      undo log
        逻辑日志，将记录恢复到它的一个特定版本
      log
    socket
      mysql.sock
    pid 文件
      pid_file 主机名.pid 内容为pid
    MySQL 表结构文件
      InnoDB 允许多个表共享若干个表空间文件
        回滚信息 rollback segment
          没有 extent
          在事务中执行updae，共享表空间的利用率会迅速上升
          事务提交或回滚并不会自动回收这些空间
          undo log segment 这个segment的数量决定了并发事务的数量。
            undo log page
可能会被多个事务的多个 undo log 复用，每一页都可以被重用，purge有自己的复杂算法决定是否删除这页的内容
              undo log
                insert undo log
                update undo log
        change buffer index page
          所有的表共用一棵 B+树，所以必然放在这里
        系统事务信息
        double write buffer
          跨表页要连续写，所以也必然放在这里
      也允许每张表使用自己的表空间文件。
每个表有自己单独的表文件，格式和内容随存储引擎变化，所以同一个库可能有若干个不同的存储引擎的表文件
        表名.ibd
这叫作 file-per-table
          tablespace
            数据段，其实也是底部的索引
            索引段，B+树的非叶子节点，页表分裂会产生这样的 Segment
            Leaf Node Segment
              Extent
                page
                  row
                    trx_id
                      6 Byte
                    rollpointer
                      7 Byte
                    col1
                    col2
                  最多允许放 16kb/2-200 行，7992行记录
                常见的 page 有8 种
                  (1) B-tree node - 数据页
                  (2) undo log page
                  (3) system page
                  (4) transaction system page
                  (5) insert buffer bitmap
                  (6) insert buffer free list
                  (7) uncompressed BLOB page
                    行逸出数据可能存在这里，也可能存在一般数据页里。
varchar 也可能存在数据逸出页里
                  (8) compressed BLOB page
              Extent
                默认大小为 1mb，压缩页会导致 extent中的页变多，但 extent 尺寸不会变化
              Extent
              Extent
            None-Leaf Node Segment
            Rollback Segment
          插入缓冲 bitmap
        格式
          antelope（羚羊）
            Compact
            Redundant
          Barracuda（酷鱼）
            Compressed
            Dynamic
      但 MySQL 会有一个统一的 .frm 文件来表达表的结构
    存储引擎文件
  表
    行
      hexdump
      溢出行
        off-page
    触发器
      Before
        Insert
        Update
        Delete
      After
        Insert
        Update
        Delete
      一张表只能建立6个触发器
    索引
      B+树
        show index from risk_blacklist_log;
          Table:索引所在表名
          Non_unique：非唯一的索引，primary key是0，因为必须是非唯一的。
          Key_name：索引名称
          Seq_in_index：索引中该列的位置
          Column_name：索引列的名称
          Collation：列以什么方式存储在索引中，可以是A或者NULL，B+树索引总是A即排序的。
          Cardinality（英[kɑ:dɪ’nælɪtɪ] 基数）：非常关键的值，表示索引中唯一值的数目的估计值。Cardinality的值除表的行数应该尽可能接近1
          Sub_part：是否是列的部分被索引。如果索引整个列显示NULL。
          packed：关键字如何被压缩，如果没有显示NULL。
          Null：是否含有NULL值。
          Index_type：索引的类型
          Comment：注释
        联合索引
          后续列不再有序，所以不是范围查询在不再有序列会失效
        覆盖索引（covering index）
          using index
        一般索引选择的顺序
          辅助索引覆盖且可排序
          辅助索引覆盖
          PK 无需回表
          辅助索引回表
        ICP 优化
          using index condition
      哈希索引
      全文索引
        检索出长文本里的任意内容
        基于 inverted index（倒排索引），存储单词和文档的映射的文件叫 auxiliary table
        mach against 支持打分和模糊匹配的逻辑
    算法
  锁
    查看锁的方法
      SHOW FULLPROCESSLIST
      SHOW ENGINE INNODB STATUS
      INFORMATION_SCHEMA
        INNODB_TRX
        INNODB_LOCKS
        INNODB_LOCK_WAITS
        8.0中没有这张表了
    锁的种类
    锁的算法
      Record Lock
      Gap-Lock
      Next-Key-Lock
        前开后闭
        previous-key-lock 则是前闭后开的
        corner case
          对唯一索引而言，查找不到记录仍然会触发 Gap-Lock，而不是锁全表
          对任意索引都会向左向右再伸展出 Gap-Lock，这样行插入总是能被挡住的-查找非常容易受 insert 和 update 影响，所以 Record Lock 主要挡 update，Gap-Lock 挡意外的 insert。
          若唯一索引有多个列，查找仅查询多个唯一索引中的其中一个，这样的查询会变成 range 查询（explain 中的 type），不是 point 查询，很容易触发 Next-Key Lock。
          范围查询，即使是简单的 <，也会锁住主键上的临界点那一行，不这样不能防止 update 改变行值的情况
    锁问题
      脏数据
      脏读
      不可重复读
      丢失更新
    阻塞
      配置
        innodb_lock_wait_timeout
          等待时间到抛出异常，MySQL 对抛出异常可能提交也可能回滚（在Java 层面通常会配置为回滚）
        innodb_rollback_on_timeout
          遇到超时是否回滚
      死锁
        wait-for-graph
        死锁检测
  事务
    事务的分类
      扁平事务（Flat Transactions）
      带保存点的扁平事务（Flat Transactions with Savepoint）
        point 意味着已完成，savepoint意味着已保存，所以无需回滚，和checkpoint意味着已刷新脏页是异曲同工的
      链事务（Chained Transactions）
      嵌套事务（Nested Transactions）
        可以用带保存点的事务（Transactions with Savepoint）来模拟
      分布式事务（Distributed Transactions）
        XA 和 JTA 可以支持
    事务的实现