1. MySQL体系结构和存储引擎
    1. 概念
      1. 数据库:物理操作系统文件或其他形式文件类型的集合,如frm、MYD、MYI、ibd结尾的文件。
      2. 实例:MySQL数据库由后台线程以及一个共享内存区组成。在系统上的表现就是一个进程。
    2. MySQL体系结构
      1. 连接池组件
      2. 管理服务和工具组件
      3. SQL接口组件
      4. 查询分析器组件
      5. 优化器组件
      6. 缓冲组件
      7. 插件式存储引擎
      8. 物理文件
    3. MySQL存储引擎
      1. 存储引擎是基于表的,而不是数据库
      2. InnoDB
        1. 主要面向在线事务处理(OLTP)应用,行锁设计、支持外键,支持类似于Oracle的非锁定读。
      3. MyISAM
        1. 不支持事务、表锁设计,支持全文索引,主要面向(OLAP)应用。存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件。
      4. NDB
        1. 是一个集群存储引擎,数据全部放在内存中。
      5. Memory
        1. 将表中的数据存放在内存中,如果数据库重启或发生崩溃,表中数据都将消失,适合存储临时数据以及数据仓库的纬度表。默认使用哈希索引。
      6. Archive
        1. 只支持INSERT和SELECT操作,使用zlib算法将row压缩后存储,适合存储归档数据。
  2. InnoDB存储引擎
    1. 体系架构
      1. 后台线程
        1. Master Thread
          1. 主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲、UNDO页的回收等。
        2. IO Thread
          1. InnoDB中大量使用了AIO来处理IO请求,IO Thread的工作主要是负责这些IO请求的回调处理。
          2. 通过`SHOW ENGINE INNODB STATUS`可以查看。
        3. Purge Thread
          1. 使用Purge Thread回收已经使用并分配的undo页。
          2. 可以在配置文件中通过`innodb_purge_threads`参数设置线程数量。
        4. Page Cleaner Thread
          1. 主要工作是脏页的刷新,为了减轻Master Thread的工作及对于用户查询线程的阻塞,进一步提高InnoDB的性能。
      2. 内存
        1. 缓冲池
          1. 通过内存的速度来弥补磁盘对数据库性能的影响
          2. 读取:从磁盘读到的页存放在缓冲池中,下一次读到相同页,若命中,直接读取该页。
          3. 修改:首先修改缓冲池中的页,然后再以一定频率刷新到磁盘。
          4. 通过`innodb_buffer_pool_size`来设置缓冲池大小
        2. LRU List、Free List和Flush List
          1. LRU List
          2. InnoDB中,缓冲池使用LRU算法来管理。不一样的是加入了midpoint位置,新读取到的页,并不是直接放入到LRU列表到首部,二是放入到LRU的midpoint位置。默认该位置在LRU列表的5/8处,可以由`innodb_old_blocks_pct`参数控制。
          3. midpoint之后的列表称为old列表,之前的列表称为new列表。可以简单理解new列表中的数据都是最活跃的热点数据。
          4. 缓冲池中页的大小默认是16KB
          5. Free List
          6. LRU列表用来管理已经读取的页,数据库刚启动时,LRU列表为空,这时的页都存放在Free列表中。当需要从缓冲池中分页时,先从Free列表中查找是否有可用的空闲页,若有则将该页从Free列表中删除放入LRU列表中,否则根据LRU算法,淘汰LRU列表末尾的页。
          7. Flush List
          8. 在LRU列表中的页被修改后,该页为脏页,即缓冲池中的页和磁盘上页的数据产生了不一致。这时数据库会通过CHECKPOINT机制将脏页刷新回磁盘。Flush列表中的页即为脏页列表。
          9. 脏页即存在于LRU列表中,也存在于Flush列表中。LRU列表用来管理缓冲池中页的可用性,Flush列表用来管理将页刷新回磁盘
        3. 重做日志缓冲
          1. 将重做日志信息先放入这个缓冲区,然后按一定频率将其刷新到重做日志文件。一般每秒钟会刷新一次。
          2. 该值可以由参数`innodb_log_buffer_size`控制,默认8MB。
          3. 刷新触发条件
          4. Master Thread每秒刷新一次;
          5. 每个事务提交时;
          6. 当重做日志缓冲池剩余空间小于1/2时。
        4. 额外的内存池
    2. CheckPoint技术
      1. 如果每次一个页发生变化就将该页的数据刷新到磁盘的开销非常大。为了保证数据库性能又避免数据丢失,采用Write Ahead Log策略。先写重做日志,再修改页。
      2. CheckPoint技术的目的是为了解决
        1. 缩短数据库的恢复时间;
        2. 缓冲池不够用时,将脏页刷新到磁盘;
        3. 重做日志不可用时,刷新脏页。
      3. 当数据库发生宕机时,只需要对Checkpoint后的重做日志进行恢复,这样大大缩短了恢复时间。
      4. 两种CheckPoint
        1. Sharp Checkpoint
          1. 发生在数据库关闭时将所有的脏页都刷新回磁盘。
        2. Fuzzy Checkpoint
          1. Master Thread Checkpoint
          2. 每秒或每10秒刷新一定比例的页。
          3. FlUSH_LRU_LIST Checkpoint
          4. InnoDB要保证LRU列表中有100个空闲页可以使用,如果少于100个,会将LRU列表尾端的页移除。如果这些页有脏页,则需要进行Checkpoint。
          5. Async/Sync Flush Checkpoint
          6. 重做日志文件不可用时,强制将一些页刷新回磁盘。
          7. Dirty Page too much Checkpoint
          8. 脏页太多了。通过参数`innodb_max_dirty_pages_pct`控制,默认值75。
    3. Master Thread 工作方式
      1. Master Thread具有最高的线程优先级别。
      2. 内部由多个循环组成
        1. 主循环
          1. 每秒操作
          2. 日志缓冲刷新到磁盘,即使这个事务还没提交(总是);
          3. 合并插入缓冲(可能);如果前一秒的IO次数小于5次,则认为当前IO压力很小,可以执行合并插入缓冲的操作。
          4. 至多刷新100个InnoDB的缓冲池中的脏页到磁盘(可能);通过判断当前缓冲池中的脏页比例是否超过`innodb_max_dirty_pages_pct`配置的值。
          5. 如果当前没有用户活动,切换到background loop(可能)。
          6. 10秒操作
          7. 刷新100个脏页到磁盘(可能);
          8. 合并至多5个插入缓冲(总是);
          9. 将日志缓冲刷新到磁盘(总是);
          10. 删除无用的Undo页(总是);
          11. 刷新100个或者10个脏页到磁盘(总是);
          12. 在1.2.x版本以后,刷新脏页的操作分离到单独的Page Cleaner Thread操作。
        2. 后台循环
          1. 删除无用的Undo页(总是)
          2. 合并20个插入缓冲(总是);
          3. 跳回到主循环(总是);
          4. 不断刷新100个页直到符合条件(可能,跳转到flush loop中完成)。
        3. 刷新循环
        4. 暂停循环
    4. InnoDB关键特性
      1. 插入缓冲
        1. Insert Buffer
          1. 对于非聚集索引的插入或更新操作,不是每次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入,否则先放入Insert Buffer中。然后再以一定的频率进行Insert Buffer和辅助索引页字节点的merge操作。
          2. Insert Buffer的使用需要同时满足
          3. 索引是辅助索引
          4. 索引不是唯一的
          5. 目前Insert Buffer错在一个问题是:在写密集的情况下,插入缓冲会占用过多的缓冲池内存,默认可以占到1/2
        2. Change Buffer
          1. 1.0.x版本后引入,相当于Insert Buffer的升级
          2. Insert Buffer
          3. INSERT
          4. Delete Buffer
          5. DELETE
          6. Purge Buffer
          7. UPDATE
        3. Insert Buffer的内部实现
          1. 一颗全局的B+树,负责对所有表的辅助索引进行Insert Buffer。存放在共享表空间中。
      2. 两次写
        1. insert buffer带来性能提升,double write可以给数据页带来可靠性。
        2. 在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是通过memcpy将脏页先复制到内存中的doublewriter buffer,之后通过doublewriter buffer再分两次,每次1MB顺序写入共享表空间的物理磁盘,然后马上调用fsync同步磁盘,避免缓冲写带来的问题。
        3. 因为doublewrite页是连续的,因此这个过程是顺序写,开销不会很大。
      3. 自适应哈希索引
        1. 哈希索引只能用来搜索等值查询
      4. 异步IO
        1. 提高磁盘操作性能
      5. 刷新邻接页
        1. 当刷新一个脏页时,innodb会检测该页所在的区的所有页,如果是脏页,会一起刷新。
  3. 文件
    1. 参数文件
      1. MYSQL可以不用参数文件,编译时或代码中有指定默认值
    2. 日志文件
      1. 错误日志
        1. SHOW VARIABLES LIKE 'log_error'来定位文件为止
      2. 慢查询日志
        1. 定位可能存在问题的SQL语句
        2. 写入慢查询通过参数long_query-time来设置,默认10s
        3. 默认不开启,通过long_slow_queries = ON开启
        4. long_queries_not_using_indexes = ON时,没使用索引的SQL也会写入慢查询日志
        5. log_throttle_queries_not_using_indexes表示每分钟允许记录到slow log的且未使用索引的SQL语句次数,默认为0,表示不限制
        6. mysqldumpslow查询慢查询日志
      3. 查询日志
        1. 记录所有对MySQL请求的信息,无论这些请求是否得到正确的执行。
      4. 二进制日志
        1. 记录对数据库执行更改的所有操作,但不包括SELECT和SHOW。UPDATE如果没改变数据不一定会写入binlog
        2. binlog作用
          1. 恢复
          2. 复制
          3. 比如主从复制
          4. 审计
          5. 对db数据审计,判断是否有数据库注入攻击
        3. 所有未提交的binlog会记录到缓存中,事务提交时直接将缓冲内的binlog写入到binlog文件中。缓冲区大小由binlog_cache_size决定,默认32K。
        4. 当一个线程开始一个事务时,会自动分配一个大小为binlog_cache_size的缓存
        5. sync_binlog=N
          1. 表示写缓冲多少次就同步到磁盘
          2. 1,表示同步写
          3. 0,默认,表示不开启
        6. mysqlbinlog用来查看binlog
    3. socket文件
    4. pid文件
    5. 表结构定义文件
      1. 以frm为后缀的文件,记录了表结构定义
    6. 存储引擎文件
      1. 表空间文件
        1. innodb将存储的数据按表空间进行存放,默认会有一个初始大侠送为10MB,名为ibdata1的文件。
        2. innodb_file_per_table,表示将每个基于表产生一个独立表空间
        3. 单独的表空间仅存储该表的数据、索引和插入缓冲BITMAP等信息。其余信息还是存在默认的表空间
    7. redo日志文件
      1. 一条记录更新时,InnoDB会先把记录写到redo log里面,并更新内存。在适当的时候,将这个记录更新到磁盘。(WAL技术)
      2. redo log是固定大小的,从头开始写,写到末尾又回到开头循环写,write pos是当前记录的位置,一边写一边后移。checkepoint是当前要擦除的位置,擦除前要把记录更新到磁盘。
      3. 如果write pos追上checkepoint,不再执行新的更新,得先擦掉一些记录,将checkpoint推进一下。
      4. 与binlog的区别
        1. redo log是InnoDB特有;binlog是Server层实现,所有引擎都有。
        2. redo log是物理日志,记录的是某个数据页上做了什么修改;binlog是逻辑日志,记录的是这个语句的原始记录
        3. redo log是循环写,空间固定会用完;binlog是追加写入,写到一定大小会切换到下一个,并不会覆盖以前的日志。
        4. binlog仅在事务提交前进行提交,只写磁盘一次;而在事务进行的过程中,不断有重做日志条目写到redolog
    1. 索引组织表
      1. innodb中,表都是根据主键顺序组织存放
      2. 如果没有显式定义主键
        1. 首先判断表中是否有非空的唯一索引,如果有,该列即为主键。
        2. 如果有多个非空唯一索引,选择建表时第一个定义的非空唯一索引为主键
        3. 否则自动创建一个6字节大小的指针
    2. innodb逻辑存储结构
      1. 表空间
        1. innodb存储引擎逻辑结构的最高层,所有数据都存放在表空间中
        1. 数据段即为B+树的叶子节点
        2. 索引段即为B+树的非索引节点
        1. 区是由连续页组成的空间,在任何情况下,每个区的大小都是1MB
        2. 默认一个页大小是16KB,一个区即64个页
        3. 页的大小可以通过innodb_page_size设置
        1. innodb磁盘管理的最小单位
        1. 每个页最多允许存放16KB/2 - 200行记录,即7992行。
    3. innodb行记录格式
      1. compact格式
        1. 变长字段长度列表
          1. 若列小于255字节,1字节表示。否则2字节表示
          2. 因为VARCHAR最大长度限制是65535
          3. 数据是逆序存放
        2. NULL标志位
          1. 指示该行数据中是否有NULL,有则用1表示
        3. 记录头信息
          1. 5字节
        4. 隐藏列
          1. 事务ID
          2. 6字节
          3. 回滚指针
          4. 17字节
        5. 若没定义主键,会增加6字节rowid
      2. Redundant格式
        1. 字段长度偏移列表
          1. 与compact长度列表一样,也是逆序存放
        2. 记录头信息
          1. 6字节
      3. 行溢出数据
        1. 一般情况,innodb的数据都存放在b-tree node中,但发生行溢出时,数据存放在uncompress BLOB二进制大对象页中
        2. BLOB、LOB不一定放在溢出页面,VARCHAR可能存放在溢出页面
        3. VARCHAR实际最大长度只能是65532,起始位和结束位占3个字节
          1. 且是所有VARCHAR列长度,如果列长度总和超过这个长度,依然无法创建表
    4. InnoDB数据页结构
      1. File Header
        1. 记录页的一些头信息
      2. Page Header
        1. 记录数据页的状态信息
      3. Infimun和Supermum Records
        1. Infimum记录比该页中任何主键值都小的值
        2. Supermum指比任何可能大的值都要大的值
        3. 这两个值在页创建时被建立,任何情况下不会被删除
      4. User Records
        1. 即行记录
      5. Free Space
        1. 是一个链表,一条记录被删除后,该空间会被加入到空闲链表
      6. Page Directory
        1. 存放记录的相对位置
        2. B+树索引本身并不能找到具体的一条记录,能找到该记录所在的页。数据库把页载入内存,然后通过Page Direcrory再进行二叉查找。
      7. File Trailer
        1. 8字节,前4字节代表该页的checksum值,后4字节代表该页最后被修改的日志序列位置LSN
        2. 每次从磁盘读取一个页会通过File Trailer检测该页的完整性
        3. 可以通过innodb_checksums来开启或关闭页完整性检测
    5. Named File Formats机制
      1. 用于解决不同版本下页结构兼容性的问题
    6. 约束
      1. 数据完整性
        1. 实体完整性保证表中有一个主键
        2. 域完整性保证数据每列的值满足特定的条件
      2. innodb的约束
        1. Primary Key
        2. Unique Key
        3. Foreign Key
        4. Default
        5. NOT NULL
      3. 约束的创建和查找
        1. 表建立时就进行约束定义
        2. 利用ALTER TABLE来创建约束
      4. 约束和索引的区别
        1. 约束是一个逻辑概念,用于保证数据的完整性
        2. 索引是一个数据结构,既有逻辑上的概念,在数据库中还代表中物理存储的方式
      5. ENUM和SET约束
      6. 触发器与约束
        1. 作用是在执行INSERT、DELETE和UPDATE之前或之后自动调用SQL语句或存储过程
        2. 创建命令:CREATE TRIGGER
        3. 一个表最多可以建立6哥触发器,INSERT、DELETE和UPDATE的BEFORE和AFTER各一个
      7. 外键约束
        1. 用于保证参照完整性
    7. 视图
      1. 视图是一个命名的虚表,由一个SQL查询来定义,没有实际物理存储。
      2. 物化视图
        1. 基于实际存在的实表,数据存储在非易失的存储设备上
        2. 可用于预先计算并保存多表的JOIN或GROUP BY等耗时比较多的SQL操作结果
        3. 对于一些复杂的统计类查询能直接查出结果
        4. 创建方式
          1. BUILD IMMEDIATE
          2. BUILD DEFERRED
    8. 分区表
      1. 概述
        1. 分区的过程是将一个表或索引分解成多个更小、更可管理的部分
        2. mysql只支持水平分区不支持垂直分区
      2. 分区类型
        1. 不论何种类型分区,如果表中存在主键或唯一索引时,分区列必须是唯一索引的一个组成部分
        2. RANGE分区
          1. 根据列值的范围分区
        3. LIST分区
          1. 与RANGE类似,只是列的值是离散的
        4. HASH分区
          1. HASH分区的目的是将数据均匀的分布到预定义的各个分区中,保证分区数据量均衡
        5. KEY分区
          1. 利用MYSQL提供的函数进行分区
        6. COLUMNS
          1. 前面的分区类型要求数据必须是整型,COLUMNS可以直接使用非整型的数据进行分区
        7. 子分区
          1. RANGE和LIST分区上还可以进行HASH和KEY子分区
        8. 分区和性能
          1. OLTP分区可能反而会使应用执行得更慢
  4. 索引和算法
    1. 概述
      1. 类型
        1. B+树索引
          1. B+树的B不是binary,而是balance
          2. B+树索引能找到的只是被查找数据行所在的页,然后数据库通过把页读入到内存,再在内存中进行查找
        2. 全文索引
        3. 哈希索引
    2. B+树
      1. 所有记录节点都是按键值的大小顺序存放在同一层的叶子节点上,由各叶子节点指针进行连接
    3. B+树索引
      1. 聚集索引
        1. 按照每张表的主键构造一颗B+树,叶子节点存放的为整张表的行记录数据,叶子节点称为数据页
        2. 每张表只能有一个聚集索引
      2. 辅助索引
        1. 叶子节点不包含行记录的全部数据,包含的是主键
        2. 每张表可以有多个
        3. 通过辅助索引来寻找数据时,Innodb存储引擎会便利辅助索引获取到指向主键索引的主键,然后再通过主键索引找到完整的行记录,这个过程叫回表
      3. 索引管理
        1. 创建/删除
          1. ALTER TABLE
          2. CREATE/DROP INDEX
        2. Fast Index Creation
          1. 快速索引创建
          2. 辅助索引创建时,对表加上S锁,因此在创建的过程中只能对该表读操作
        3. Online DDL
          1. 原理是执行创建或删除操作时,将INSERT、UPDATE、DELETE这类DML操作日志写入一个缓存中。完成索引创建后再将redo应用到表上
    4. Cardinality值
      1. 索引中不重复数记录数量到预估值
      2. Cardinality/n_rows_in_table应尽可能接近1
      3. 更新
        1. 采样统计
        2. 表中1/6的数据发生过变化时
        3. 修改的行超过20亿次时,行内容不一定要改变
    5. B+树索引的应用
      1. 联合索引
        1. 指对表上的多个列进行索引
        2. 联合索引的键值数量大于2
      2. 覆盖索引
        1. 即从辅助索引中就可以得到查询的记录
        2. 辅助索引不包含整行记录的所有信息,故大小要远小于聚集索引,可以减少大量的IO操作
      3. 索引提示
        1. SELECT时通过USE INDEX指定
        2. USE INDEX只是告诉优化器可以选择该索引,实际上优化器还是会根据自己的判断进行选择
        3. 如果需要明确指定某个索引则使用FORCE INDEX
    6. 哈希算法
      1. innodb采用除法hash方式
      2. 自适应哈希索引
        1. 数据库自身创建并使用,DBA不能对其进行干预
    7. 全文检索
      1. 全文检索是将存储于数据库中的整本书或整篇文章中的任意内容查找出来
      2. 倒排索引
        1. 全文检索通常使用倒排索引来实现
        2. 在辅助表中存储来单词和单词自身在一个或多个文档中所在位置之间的映射
      3. innodb全文检索
        1. 限制
          1. 每张表只能有一个全文检索索引
          2. 由多列组合而成的全文检索索引列必须使用相同的字符集与排序规则
          3. 不支持没有单词界定符的语言,如中文、日语、韩语等
        2. 语法
          1. MATCH() ··· AGAINST()
    1. 锁用于管理对共享资源的并发访问
    2. lock和latch
      1. latch是轻量级的锁,要求锁定的时间必须非常短
        1. mutex
        2. rwlock
        3. 用于保证并发线程操作临界资源的正确性,通常没有死锁检测的机制
      2. lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。
    3. Innodb中的锁
      1. 锁的类型
        1. 共享锁(S Lock)允许事务读一行数据
        2. 排他锁(X Lock)允许事务删除或更新一行数据
        3. 意向锁
          1. 即为表级别的锁,设计的目的为了在一个事务中揭示下一行将被请求的锁类型。
          2. 类型
          3. 意向共享锁(IS Lock)事务想要获得一张表中某几行的共享锁
          4. 意向排他锁(IX Lock)事务想要获得一张表中某几行的排他锁
      2. 可以通过SHOW ENGINE INNODB STATUS查看当前锁请求的信息
      3. 一致性非锁定读
        1. 指innodb通过多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在DELETE或UPDATE,这时读取不会去等待行上锁的释放,而是读取行的快照数据
        2. 一个行记录可能有不止一个快照数据
        3. 事务隔离级别为REPEATABLE READ模式以下,SELECT操作使用一致性非锁定读
      4. 一致性锁定读
        1. 两种一致性锁读
          1. SELECT FOR UPDATE
          2. 加X锁
          3. SELECT LOCK IN SHARE MODE
          4. 加S锁
      5. 自增长与锁
        1. 自增长计数器采用AUTO-INC Locking实现
        2. 为了提高插入性能,锁不是一个事务完成后才释放,而是完成自增长插入SQL语句以后立即释放
        3. Innodb中,自增长值必须是索引,且必须是索引的第一列
      6. 外键和锁
        1. 对于外键列,如果没有显式加索引,innodb会自动加一个索引,可以避免表锁
        2. 对外键值的插入或更新,会对父表加一个S锁。如果这时父表加了X锁,子表对操作会被阻塞
    4. 锁的算法
      1. Record Lock
        1. 单行记录上的锁
      2. Gap Lock
        1. 锁定一个范围,但不包含记录本身
        2. 为了阻止多个事务将记录插入到同一范围内,但是会导致幻读现象
        3. 关闭Gap Lock
          1. 将事务的隔离级别设置为READ COMMITTED
          2. 将参数innodb_locks_unsafe_for_binlog设置为1
      3. Next-Key Lock
        1. Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身
        2. 当查询当列是唯一索引时,Next-Key Lock会降级为Record Lock
      4. 解决幻读
        1. 幻读指同一事务下,连续执行两次同样的SQL语句可能会有不同的结果。第二次的SQL语句可能会返回之前不存在的行
        2. 采用Next-Key Lock解决
    5. 锁问题
      1. 脏读
        1. 指在不同的事务下,当前事务可以读到另外事务未提交的数据
        2. 脏页与脏数据
          1. 脏页指在缓冲池中已经被修改读页,但还没有刷新到磁盘中,而脏数据指事务对缓冲池中行记录对修改,并且还没有被提交
          2. 脏页读取是正常的,而脏数据读取指读取到未提交到数据,违反了数据库到隔离性
        3. 脏读发生的条件是隔离级别未READ UNCOMMITTED,所以只要隔离级别大于RUC即可解决
      2. 不可重复读
        1. 指一个事务内多次读取同一个数据集合,在这个事务还没结束时,另外一个事务也访问该同一数据集合,并做了一些DML操作。那么这个事务两次读到的数据可能不一样
        2. 不可重复读和脏读区别
          1. 脏读是读到未提交的数据
          2. 不可重复读读到的是已经提交的数据,但违反了数据库事务一致性的要求
        3. 在Next-key lock算法下,对于索引的扫描,不仅是锁住扫描的索引,而且还锁住这些索引覆盖的范围。因此在这个范围内的插入都是不允许的,这样就避免了另外的事务在这个范围内插入数据导致的不可重复读的问题。
      3. 丢失更新
        1. 指一个事务的更新操作会被另一个事务的更新操作所覆盖,从而导致数据不一致
        2. 避免丢失更新发生,需要让事务串行化
    6. 阻塞
      1. 指一个事务中的锁需要等待另一个事务中的锁释放它所占的资源
      2. 通过innodb_lock_wait_timeout来控制等待时间
    7. 死锁
      1. 死锁指两个或者两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象
      2. 解决死锁问题最简单的方式是超时,当两个事务互相等待时,其中一个超时回滚,另一个就能继续进行。
      3. 采用wait-for graph的方式来进行死锁检测
    8. 锁升级
      1. 指将当前锁的粒度降低
      2. 触发锁升级条件
        1. 由一句单独的SQL语句在一个对象上持有的锁的数量超过来阈值(默认5000)
        2. 锁资源占用的内存超过来激活内存的40%时
      3. innodb不存在锁升级的问题,因为其不是根据每个记录来产生行锁的,而是根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中多少记录,其开销通常都是一致的。
  5. 事务
    1. 事务是访问并更新数据库中各种数据项的一个持续执行单元。在事务中的操作,要么都修改,要么都不修改。
    2. 事务分类
      1. 扁平事务
        1. 所有操作处于同一层次,期间操作是原子的
      2. 带有保存点的扁平事务
        1. 允许在事务执行过程中回滚到同一事务中较早的一个状态
      3. 链事务
        1. 与👆的类似,带有保存点的扁平事务能回滚到任意正确的保存点,链事务只能回滚到最近的一个保存点
      4. 嵌套事务
        1. 一个层次结构,由顶层事务控制这各各层次的事务
      5. 分布式事务
        1. 在一个分布式环境中运行的扁平事务
    3. 事务的实现
      1. redo log
        1. 基本概念
          1. redo log用来实现事务的持久性,即ACID中的D
          2. 由内存中的redo log buffer和redo log file组成
          3. 当事务提交时,必须先将该事务的所有日志写入到redo log文件进行持久化
          4. 基本都是顺序写,在数据库运行时不需要对redo log的文件进行读取操作
          5. innodb_flush_log_at_trx_commit用来控制redo log刷新到磁盘的策略
          6. 默认为1
          7. 事务提交时必须调用一次fsync
          8. 0
          9. 事务提交时不进行写入redo log操作,只在master thread中每秒fsync一次
          10. 2
          11. 事务提交时写入redo log,但仅写入文件系统的缓存中。不进行fsync操作
        2. log block
          1. redo log buffer和redo log file都是以块的方式存储的,每块大小512字节
          2. 由于redo log block和磁盘扇区大小一样,因此redo log的写入可以保证原子性,不需要doublewrite技术
        3. log group
          1. 由多个redo log file组成,每个日志文件大小相同
          2. log buffer刷新到磁盘规则
          3. 事务提交时
          4. 当log buffer中有一半当内存空间已经被使用时
          5. log checkpoint时
        4. redo log格式
          1. 头部格式
          2. redo_log_type
          3. space
          4. 表空间的ID
          5. page_no
          6. 页的偏移量
        5. LSN
          1. 日志序列号,8个字节,单调递增,表示事务写入redo log的字节总量
          2. 含义
          3. redo log写入的总量
          4. checkpoint的位置
          5. 页的版本
        6. 恢复
          1. innodb在启动时不管上次数据库是否正常关闭,都会尝试进行恢复操作
      2. undo log
        1. 基本概念
          1. 与redo log存放在日志文件中不同,undo存放在数据库内部的一个特殊的段中,即undo段。位于共享表空间内
          2. 用来保证事务的一致性
          3. 用来帮助事务回滚及MVCC
          4. undo log是需要进行随机读写的
          5. undo是逻辑日志,只是将数据库逻辑地恢复到原来的样子,所有修改都被逻辑地取消了,但数据结构和页本身在回滚之后可能大不相同
        2. undo存储管理
          1. innodb有一个rollback segment,每个回滚段中记录了1024个undo log segment,每个undo log segment中进行undo页的申请
          2. 事务提交时,undo处理
          3. 将undo log放入列表中,以供之后的purge操作
          4. 判断undo log所在的页是否可以重用,若可以分配给下个事务使用。
          5. 事务提交后并不能马上删除undo log及其所在的页。因为可能还有其它事务需要通过undo log来得到行记录之前的版本。是否能够最终删除,由purge线程来判定
        3. undo log格式
          1. insert undo log
          2. 在insert操作中产生的,由于insert操作的记录只在本事务中可见,该undo log可以在事务提交后直接删除
          3. update undo log
          4. delete和update产生的,可能需要提供MVCC机制,因此不能在事务提交时进行删除。提交时放入undo log 链表,等待purge线程进行最后删除。
      3. purge
        1. 用于最终完成delete和update操作
        2. 由于innodb支持MVCC,可能在事务提交时其它事务正在引用这行,故需要保存之前的版本。若该行记录已不被任何其它事务引用,那么就可以进行真正的delete。
      4. group commit
        1. 即一次fsync可以刷新确保多个事务日志被写入文件
        2. 事务提交的两阶段操作
          1. 参考:https://jin-yang.github.io/post/mysql-group-commit.html
    4. 事务控制语句
      1. START TRANSACTION | BEGIN
        1. 显示开启一个事务
      2. COMMIT
        1. 提交事务,并对数据库进行所有修改成为永久性的
      3. ROLLBACK
        1. 结束事务,并撤销正在进行的所有未提交的修改
      4. SAVEPOINT
        1. 创建一个保存点,一个事务中可以由多个保存点
      5. RELEASE SAVEPOINT
        1. 删除一个事务的保存点
      6. ROLLBACK TO [SAVEPOINT]
        1. 把事务回滚到保存点
      7. SET TRANSACTION
        1. 设置事务的隔离级别
    5. 事务的隔离级别
      1. 读未提交
        1. select不加锁,可能出现读脏
      2. 读提交
        1. 普通select快照读,锁select /update /delete 会使用Record Lock,可能出现不可重复读
      3. 可重复读
        1. innodb默认
        2. 普通select快照读,锁select /update /delete 根据查询条件情况,会选择Record Lock,或者Gap Lock / Next-key Lock,以防止幻读
      4. 串行化
        1. select隐式转化为select ... in share mode,会被update与delete互斥
  6. 备份与恢复
    1. 备份的方法
      1. 冷备
        1. 数据库停止时备份,最为简单,一般只需要复制相关的数据库物理文件即可
      2. 热备
        1. 数据库运行中直接备份,并且对运行中对数据库操作没有任何影响
        2. 子主题 2
      3. 温备
        1. 数据库运行中进行,但会对当前数据库对操作有所影响。如加一个全局读锁以保证备份数据对一致性
    2. 备份后文件内容
      1. 逻辑备份
        1. 指备份出的文件内容时可读的,一般为文本文件,内容为一条条SQL语句或者表内实际数据
        2. 如mysqldump和SELECT * INTO OUTFILE
      2. 裸文件备份
        1. 指复制数据库的物理文件
        2. 如ibbackup、xtrabackup这类工具
    3. 备份的内容
      1. 完全备份
      2. 增量备份
      3. 日志备份
        1. 通过binlog备份
    4. mysql的复制
      1. 复制是mysql通过高可用解决方案
      2. 步骤
        1. master把数据更改记录到binlog中
        2. slave把master的binlog复制到自己的relay log中
        3. slave重做relay log中的日志,把更新应用到自己的数据库中,以达到数据一致性