# mysqlStudy
**Repository Path**: zhayan/mysql-study
## Basic Information
- **Project Name**: mysqlStudy
- **Description**: mysql学习记录
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-01-10
- **Last Updated**: 2022-01-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# mysqlStudy
## 架构原理
### 体系架构
#### 网络连接层
客户端连接器,提供与MYsql服务器连接建立支持。
#### 服务层
- 连接池(Connection Pool)
负责存储和管理客户端与数据的连接,一个线程负责管理一个连接
- 系统管理和控制工具(Management Services & Utilies)
备份恢复、安全管理、集群管理等
- SQL接口(Sql Interface)
用于接受客户端发送的各种sql命令,并且返回用户的查询结果。DML/DDL/存储过程、识图、触发器等。
- 解析器(Parser)
负责将请求的SQL解析生成一个“解析树”,返回根据mysql规则检查解析数是否合法
- 查询优化器(Optimizer)
当“解析树”通过解析器语法检查后,将交由优化器将其转化为执行计划,然后与存储引擎交互。
- 缓存(Cache&Buffer)
存储机制由一系列小缓存组成,如表缓存、记录缓存、权限缓存、引擎缓存等。如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据
#### 存储引擎层(Pluggable Storage Engines)
负责MYSQL中数据的存储与提取,与底层系统文件进行交互。插件模式,服务器中的查询执行引擎通过接口与存储引擎进行通讯,接口屏蔽了不同存储引擎之间的差异。
#### 系统文件层(File System)
负责将数据库的数据和日志存储在文件系统上,并完成与存储引擎的交互,是文件的物理存储层。包含:日志文件、新数据文件、配置文件、pid文件、socket文件等。
1. 日志文件:
- 错误日志(error log):
默认开启,`show variables like '%log_error%';`
- 通用查询日志(general query log):
记录一般查询语句,`show variables like '%general%';`
- 二进制日志(binary log):
记录对mysql数据库执行的更改操作,并记录了语句的发生时间,执行时长;但是不记录select、show等不修改数据库的sql。主要用于数据库恢复和主从复制。
`show variables like '%log_bin%'; //是否开启`
`show variables like '%binlog%'; //参数查看`
`show binary log; //查看日志文件`
- 慢查询日志(Slow query log)
记录所有执行时间超时的SQL,默认10秒。
`show variables like '%slow_query%'; //是否开启`
`show variables like '%long_query_time%'; //时长`
2. 配置文件:用于存储myssql富哦you的配置信息文件,my.cnf、my.ini等
3. 数据文件:
- dp.opt:记录库默认使用的字符集和校验规则。
- frm:存储与表相关的源数据信息,表结构的定义信息,每一张表有一个frm文件。
- MYD文件:MyISAM存储引擎专用,存放MyISAM表的数据,每一张表有一个。MYD文件。
- MYI文件:
- ibd文件和IBDATA文件:存放InnoDB的数据文件,包括索引。ibd独享表空间文件,每张表一个;ibdata共享表空间文件,多表可共享一个.ibdata文件。
- ibdata1文件:系统表空间数据文件,存储表源数据、Undo日志等。
- ib_logfile0、ib_logfile1文件:Redo log日志文件。
4. pid文件
pid文件是mysqld应用程序在Unix、Linux环境下的一个进程文件,存放自己的进程id。
5. socket文件
Unix/Linux环境下,可以通过Unix Socket连接mysql。
### 运行机制

`show processlist; //查看用户正在运行的线程信息`
`show variables like '%query_cache%'; //查询缓存是否开启信息`
`show status like 'Qcahe%'; //查看缓存配置详情`
### 存储引擎
`show engines; //查看当前数据库支持的存储引擎`
- Innodb:支持事务,可提交、回滚、崩溃恢复;事务安全。5.5之后默认。
- MyISAM:不支持事务和外键,访问速度快。hibernate_sequence自增表就是。5.5版本之前默认。
- Memory:内存表,默认使用hash索引,访问速度快,但停机数据丢失。
- Archive:归档类型引擎,仅支持insert、select语句
- Csv:已csv文件进行数据存储,所有列必须强制指定not null,且不支持索引和分区,适合做数据交换的中间表
- BlackHole:黑洞,只进不出,数据不进行保存
- Federated:可以访问远端mysql数据库中的表。一个本地表,不保存数据,访问远端表数据
- MRG_MyISAM:一组MyISAM表的组合,表结构相同;Merge表本身没有数据,对Merge按操作可以对一组MyISAM表进行操作。
#### InnoDB和MyISAM
| | InnoDB | MyISAM |
| ------ | ------------------------------- | ---------------------------------------- |
| 事务和外键 | 支持,具有安全性和完整性。 | 不支持;提供高速存储和检索 |
| 锁机制 | 支持行级锁,锁定指定记录。基于索引来加锁实现。 | 表级锁,锁定整张表 |
| 索引结构 | 聚集(聚簇)索引,索引和记录在一起存储。 | 使用非聚集(聚簇)索引,索引和记录分开。 |
| 并发处理能力 | 读写阻塞与隔离级别有关,采用MVCC多版本并发控制来支持高并发 | 使用表锁,写操作并发率低;读之间并不阻塞,读写阻塞。 |
| 存储文件 | 两个文件:frm表结构、ibd数据文件,最大支持64TB | 三个文件:frm表结构、myd表数据结构、myi索引文件。5.0开始默认限制256TB |
| | | |
#### InnoDB存储结构

##### 内存结构
- Buffer Pool:缓冲池
以Page也为单位,默认16K;底层使用链表管理Page;在InnoDB访问表记录和索引时会在Page页中缓存,以后使用可以减少磁盘IO操作,提升效率。
- Page管理机制
| page分类(状态) | 描述 |
| ---------- | ---------------------------------- |
| free page | 空闲page,未被使用 |
| clean page | 被使用page,数据没有被修改过 |
| dirty page | 脏页,被使用page,数据被修改过,页中数据和磁盘的数据产生了不一致 |
| 链表结构链表结构 | 描述 |
| ---------- | ---------------------------------------- |
| free list | 空闲缓冲区,管理free page |
| flush list | 需要刷新到磁盘的缓冲区,管理dirty page,内部page按修改时间排序。
脏页即存在flush链表,也在LRU链表中,但互不影响;LRU链表负责管理page的可用性和释放;flush链表负责管理脏页的刷盘操作 |
| lru list | 正在使用的缓冲区,管理clean/dirty page,缓冲区以midpoint为基点。前面链表称为new列表区,存放经常访问的数据,占63%;后面的链表称为old列表区,存放使用较少的数据,占37% |
- 改进型LRU算法维护
| LRU类型 | 描述 |
| ------ | ---------------------------------------- |
| 普通LRU | 末尾淘汰法,新数据从链表头部加入,释放空间时从末尾淘汰 |
| 改进型LRU | 链表分为new和old两部分。加入元素是从中间midpoint位置插入,如果数据很快被访问,那么page就会向new列表头部移动;如果数据没有被访问,会逐步向old尾部移动,等待淘汰 |
每当有新的page数据读取到buffer pool时,InnoDB引擎会判断是否有空闲页,是否足够,如果有就将free page从free list列表删除,放入到LRU列表中。没有空闲页,就会根据LRU算法淘汰LRU链表默认的页,将内存空间释放分配给新的页。**如果空间均不足呢??**
- Buffer Pool配置参数
建议:**将innodb_buffer_pool_size设置为总内存大小的60-80%,innodb_buffer_pool_intances可以设置为多个,避免缓存争夺。**
| `show variables like '%innodb_page_size%'; //查看page页大小` |
| ---------------------------------------- |
| `show variables like '%innodb_old%'; //查看lru list中old列表参数` |
| `show variables like '%innodb_buffer%'; //查看buffer pool参数` |
- Change Buffer写缓冲区CB
在进行DML操作时,如果没有其响应的Page数据,并不会like将磁盘页加载到缓冲池,而是在CB中记录缓冲变更,等未来数据被读取时,再将数据合并恢复到BP中。
占用Buffer Pool空间,默认占25%,最大允许占50%,`innodb_change_buffer_max_size`
当更新一条数据时。该记录在Buffer Pool中存在,则直接在Buffer Pool修改,一次内存操作;如果不在BP中,直接在ChangeBuffer中进行一次内存操作,不再去磁盘查询,避免一次磁盘IO。当下次记录查询时,会进行磁盘读取,然后再从CB中读取信息合并,最终载入BufferPool中。
**写缓冲区,仅适用于非唯一普通索引页:**
- 如果再索引设置唯一性,在修改时,InnoDB必须要做唯一性校验,因此必须查询磁盘,做一次IO操作。会直接将记录查询到BufferPool中,然后再缓冲池修改,不会在ChangeBuffer操作。
- Adaptive Hash Index自适应哈希索引
用于优化对BP数据的查询。InnoDB存储引擎会监控对表索引的查找,如果观察到建立hash索引可以带来速度的提升,则会建立hash索引,所以称之为自适应。自动根据访问的频率和模式来为某些页建立hash索引
- Log Buffer日志缓冲区
用于保存要写入磁盘上log文件(redo/undo)的数据,内容定期刷到磁盘log文件中。日志缓冲区满时会自动将其刷新到磁盘,当遇到BLOB或多行更新的大事务操作时,增加日志缓冲区可以节省磁盘IO。
主要用于记录InnoDB引擎日志,在DML操作时会产生redo/undo日志。
空间满了,会自动写入磁盘。`innodb_log_buffer_size`参数调大可以减少磁盘IO频率。
`innodb_flush_log_at_trx_commit`控制日志刷新行为,默认为1。
| 参数 | 描述 |
| ---- | ---------------------------------------- |
| 0 | 每隔1秒写日志文件和刷盘操作。写日志文件LogBuffer -> OS cache,刷盘OS cache -> 磁盘文件;最多丢失1秒的数据 |
| 1 | 事务提交,立交写日志文件和刷盘,数据不丢失,但会频繁IO |
| 2 | 事务提交,立刻写日志文件,每隔1秒进行刷盘操作 |
##### 磁盘结构
- Tablespaces表空间
用于存储表结构和数据。
| 表空间类别 | 描述 |
| ------------------------------- | ---------------------------------------- |
| 系统表空间The System Tablespace | 包括InnoDB数据字典,Doublewrite Buffer,Change Buffer,Undo Logs的存储区域。默认包含任何用户在系统表空间创建的表数据和索引数据。是一个共享的表空间,被多个表共享。
`innodb_data_file_path`,默认值ibdata:12M:autoextend,文件名ibdata1、12M、自动扩展 |
| 独立表空间File-Per-Table Tablespaces | 单表表空间,创建于自己的数据文件中。当`innodb_file_per_table`选项开启时,表将被创建于表空间中。否则创建于系统表空间中。每个表文件表空间由一个`.ibd`数据文件代表,默认被创建于数据库目录中。支持动态和压缩行格式。 |
| 通用表空间General Tablespaces | 通过`create tablespace`创建共享表空间。可以创建mysql数据目录外的其他表空间,可以容纳多张表,且支持所有的行格式。 |
| 撤销表空间Undo Tablespaces | 由一个或多个包含undo日志文件组成。5.7版本之前Undo占用System Tablespace共享区,之后分离。
`innodb_undo_tablespaces`控制,默认0;0,表示使用系统表空间ibdata1;大于0表示使用undo表空间undo_001/undo_002等 |
| 临时表空间Temporary Tablespaces | 分为session/global temporary tablespace;前者存储用户创建的和磁盘内部的临时表;后者存储用户临时表的回滚段(rollback segments)。mysql服务器正常关闭或异常终止时,临时表空间将被移除,每次启动时会被重新创建。 |
- 数据字典InnoDB Data Dictionary
由内部系统表组成,这些表包含用于查找表、索引和表字段等对象的元数据。元数据物理上位于InnoDB系统表空间中。历史原因,数据字典元数据一定程度上与frm文件信息重叠。
- 双写缓冲区Doublewrite Buffer
一个存储区域。在BufferPool的page页刷新到磁盘真正位置前,会先在该缓冲区存储。如果page写入过程中出现操作系统、存储子系统、mysqld进程奔溃,InnoDB可以再奔溃恢复期从该缓冲区中找到页面的备份。
`innodb_doublewrite=0 //禁用`
开启时建议将`innodb_flush_method`设为O_DIRECT;控制innodb数据文件及redo log的打开、刷写模式。
| fdatasync | 默认;先写入操作系统缓存,然后再调用fsync()函数去异步刷写数据文件与redo log的缓存信息。 |
| --------- | ---------------------------------------- |
| O_DSYNC | |
| O_DIRECT | 数据文件先写入操作系统会通知操作系统不要缓存数据,也不要用预读,直接从InnoDB buffer写到磁盘文件 |
- 重做日志Redo Log
用于崩溃恢复期间更正不完整事务写入的数据。mysql以循环方式写入重做日志文件,记录InnoDB中所有对Buffer pool修改的日志。当出现实例故障,导致数据未能更新到数据文件,则数据库重启时需undo,重新把数据更新到数据文件。读写事务执行时都会产生redo log。默认情况下,以ib_logfile0、ib_logfile1物理文件表示。
- 撤销日志Undo Logs
是在事务开始前保存的被修改数据的备份,用于例外情况的回滚事务。撤销日志属于逻辑日志,根据每行记录进行记录。存在于系统表空间、撤销表空间和临时表空间中。
#### InnoDB线程模型

| 类型 | 描述 |
| ------------------- | ---------------------------------------- |
| IO Thread | AIO,提高性能。
write thread:负责写,将缓存脏页刷新到磁盘,4个
read thread:负责读取,将数据从磁盘加载到缓存page页,4个
insert buffer thread:负责将写缓存内容刷新到磁盘,1个
log thread:负责将日志缓冲区内容刷新到磁盘,1个 |
| Purge thread | 事务提交后,回收已经分配的不再需要的undo页。
`show variables like '%innodb_purge_threads%';` |
| Page cleaner thread | 将脏数据刷新到磁盘,刷盘后redo log可以被覆盖,所以即可以同步数据,又能redo log循环使用。会调用write thread处理。
`show variables like '%innodb_page_cleaners%';` |
| Master Thread | mysql主线程,负责调度其他各线程,优先级最高。作用是将缓冲池中的数据异步刷新到磁盘,保证数据的一致性。包括:脏页的刷新、undo页回收、redo日志刷新、合并写缓冲等。
内部两个主处理,分别每隔1秒、10秒处理。
每隔一秒的操作:
- 刷新日志缓冲区到磁盘
- 合并写缓冲区数据,根据IO读写压力来决定是否操作
- 刷新脏页数据到磁盘,达到75%才操作。`innodb_max_dirty_pages_pct`和`innodb_io_capacity`
每隔10秒的操作:
- 刷新脏页数据到磁盘
- 合并写缓冲区数据
- 刷新日志缓冲区
- 删除无用的undo页 |
#### InnoDB数据文件
##### 文件存储结构

##### 文件存储格式
`show table status;`
##### File文件格式
- Antelope:5.6及以前,提供行格式:COMPACT/REDUNDANT
- Barracuda:5.7开始,支持之前的行格式并提供新的:COMPRESSED/DYNAMIC
##### Row行格式
每个表的数据分成若干页来存储,每个页中采用B树结构存储。如果某些字段信息过长,无法存储在B树节点中,这时被单独分配空间,称为溢出页。
`ALTER TABLE [table_name] ROW_FORMAT=格式类型;`
| 行格式 | 描述 |
| ---------- | ---- |
| REDUNDANT | |
| COMPACT | |
| DYNAMIC | |
| COMPRESSED | |
#### Undo Log
撤销或取消,以撤销操作为目的,返回指定某个状态的操作。
- 在事务开始前产生;事务提交时,不会立马删除,innodb将undo log放入删除列表中,后面通过后台线程purge thread进行回收。
- 逻辑日志:如执行delete,undolog中记录一个insert;执行update,undolog中记录一个反向的update。
- 采用段的方式管理和记录。rollback segment回滚段,内部包含1024个undo log segment。`show variables like'%innodb_undo%';`
作用:
- 实现事务原子性:事务执行失败则rollback,mysql利用undo log恢复到事务开始之前的状态
- 实现多版本并发控制MVCC:事务未提交前,undo log保存了未提交之前的数据版本,可以提供给其他并发的事务进行快照读。
#### Redo Log
重做恢复,以恢复操作为目的。事务中修改的任何数据,将最新的数据备份存储。
- 随着事务操作的执行,就会生成redo log,在事务提交时会将尝试的redo log写入log buffer,并不随事务提交立刻写入磁盘文件。等事务操作的脏页写入磁盘后,占用的空间可以重重(覆盖写入)
- 为了实现事务的持久性:防止在发生故障的时间点,尚有脏页未写入表的IBD文件中,在重启mysql服务的时候根据Redolog进行重做,达到持久化。
- 文件内容以顺序循环的方式写入文件,写满时回溯到第一个文件,进行覆盖写。
相关配置:每个innodb引擎至少有一个重做日志文件组group,每个文件组至少有2个重做日志文件,`ib_logfile0/ib_logfile1`,查看`show variables like '%innodb_log%';`。
redo buffer持久化策略:`innodb_flush_log_at_trx_commit`。
| 参数 | 描述 |
| ---- | ---------------------------------------- |
| 0 | 每秒提交Redo buffer -> os cache -> flush cache to disk,可能丢失一秒内的事务数据。master线程每1秒操作。 |
| 1 | 默认值。每次事务提交执行Redo buffer -> os cache -> flush cache todisk,最安全性能最差。 |
| 2 | 事务每次提交执行Redo buffrt -> os cache,然后master每隔1秒执行os cache -> flush to disk。一般选该值。 |
#### Binlog
binary log二进制日志,属于mysql server自己的日志。
- 记录所有数据库表结构变更以及表数据修改的二进制日志,不包括select、show等类似操作。以事件形式记录,包括执行的消耗时间。
- 使用场景:主从复制、数据恢复。
- 文件名:默认`主机名_binlog-序列号`,如oak_binlog-000001
| 记录模式 | 描述 |
| ------------------------------------ | ---------------------------------------- |
| ROW-row based replication | 日志中记录每一行数据被修改的情况,然后再slave端对相同的数据进行修改。 |
| STATMENT-statement based replication | 每一条被修改数据的sql都记录到master的Binlog中,slave复制的时候sql进程会解析成和原理master端执行过相同的sql再次执行。简称sql语句复制。 |
| MIXED-mixed-based replication | 混合模式。 一般会使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择写入模式 |
binlog对应不同的事件:query event、row event、xid event。
写入机制:
文件操作:
## 索引原理
### 索引类型
| 索引类型 | 描述 |
| ---- | ---- |
| 普通索引 | |
| 唯一索引 | |
| 主键索引 | |
| 复合索引 | |
| 全文索引 | |
### 索引原理
- 二分查找法
- hash结构
- B+树
- 聚簇索引
- 二级(辅助)索引
- 非聚簇索引
- B-树
### 索引分析与优化
#### explain
- select_type:查询的类型
- SIMPLE:查询语句不包含子查询或union
- PRIMARY:此查询是最外层的查询
- UNIOM:此查询是UNION的第二个或后续查询
- DEPENDENT UNION
- UNION RESULT
- SUBQUERY:
- DEPENDENT SUBQUERY:
- type:存储引擎查询数据时采用的方法
- ALL:全表扫描,性能最差
- index:基于索引的全表扫描,先扫描索引再全表扫描
- range:索引范围查询。使用>、>=、<、<=、in等
- ref:使用唯一索引进行单值查询
- eq_ref:一般为多表join查询,前面表的每一个记录,都只能匹配后面表的一行结果
- const:使用主键或唯一索引做等值查询,常量查询
- NULL:不用访问表,速度最快
- possible_keys:可能用到的索引
- key:真正使用到的索引名称
- rows:估算结果需要扫描的记录行数,越少效率越高
- key_len:传使用索引的字节数量。可以判断是否全部使用了组合索引
- Extra
- Using where:查询需要通过索引回表查询数据
- Using index:通过索引就能查询到数据
- Using filesort:查询出来的结果需要额外排序,数据量小在内存,大则在磁盘中,可进行优化
- Using temprorary:查询使用了临时表,一般出现与去重、分组等操作
- index condition pushdown
#### 分析类型
| 类型 | 描述 |
| ------ | ---------------------------------------- |
| 回表查询 | 辅助索引的叶子节点存储的是主键值和索引字段值,通过辅助索引无法直接定位行记录,通常情况下,需要扫码两遍索引树。先通过辅助索引定位主键值,然后再通过聚簇索引定位行记录,这就叫做回表查询,它的性能比扫一遍索引树低 通过索引查询主键值,然后再去聚簇索引查询记录信息 |
| 覆盖索引 | 只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快,这就叫做索引覆盖。 将被查询的字段,建立到组合索引 |
| 最左前缀原则 | 最左优先,即查询中使用到最左边的列,那么查询就会使用到索引,如果从索引的第二列开始查找,索引将失效 |
| LIKE查询 | MySQL在使用Like模糊查询时,索引是可以被使用的,只有把%字符写在后面才会使用到索引。 |
| Null查询 | 可以在含有NULL的列上使用索引,但NULL和其他数据还是有区别的,不建议列上允许为NUL |
| | |
#### 索引与排序
### 查询优化
#### 慢查询定位
开启慢查询日志
`show variables like 'slow_query_log%';`
```
set global slow_query_log = ON;
set global slow_query_log_file = '***.log';
set global log_queries_not_using_indexes = ON; // 记录没有使用索引的查询
set long_query_time = 10; // 单位秒
```
查看工具mysqldumpslow
```
// mysql bin目录下执行-windows需要perl额外工具
perl mysqldumpslow.pl --help
perl mysqldumpslow.pl -t 5 -s at path[slow.log]
-t N,top n,返回前面多少条数据
-s,order顺序, al平均锁定时间
ar平均返回记录时间
at平均查询时间(默认)
c计数
l锁定时间
r返回记录
t查询时间
-g,正则匹配模式,大小写不敏感
```
#### 慢查询优化
- 是否慢查询:sql执行时间 > long_query_time
- 是否应用了索引:explain,key是否为null
- 应用索引是否row减少(索引过滤性):扫描少则快,若row不变则索引无效
提高索引过滤性:
- 索引字段差异要大:
- 增加虚拟列:`alter table [table_name] add first_name varchar(2) generated always as (left(name, 1), add index(first_name, age));`
总结:
- 全表扫描:explain分析中type属性为all
- 全索引扫描:explain分析中type属性index
- 索引过滤性不好:靠索引字段选型、数据量和状态、表设计
- 频繁回表查询:尽量少用select *,尽量保证索引覆盖
#### 分页查询优化
`select * from [table_name] limit [offset],[rows]`
- 偏移量offset
- 返回记录行数rows
优化方案:
- 利用索引覆盖,select尽量取想要的值
- 利用子查询优化:让子查询走索引(覆盖),主查询尽量走索引
## 事务与锁
### ACID特性
### 事务控制
| 事务并发 | 描述 |
| ----- | ---------------------------------------- |
| 更新失败 | 多个事务更新同一行记录产生丢失现象。
- 回滚覆盖:一个事务回滚,把其他已提交事务覆盖。
- 提交覆盖:一个事务提交,把其他已提交事务覆盖 |
| 脏读 | 一个事务读取到了另一个事务修改但未提交的数据 |
| 幻读 | 一个事务中多次按相同条件查询,结果不一致。后续结果或多或少 |
| 不可重复读 | 一个事务中多次读取同一行记录,前后读取不一致 |
#### MVCC
multi version concurrency control多版本并发控制。
- 读读并行
- 读写并行
- 写读并行
- ~~写写并行无法支持~~:可以使用乐/悲观锁
读操作:
- 快照读Snapshot Read
读取记录的快照版本,不用加锁
- 当前读Current Read
读取记录的最新版本,并且当前读返回的记录都会加锁,保证其他事务不再并发修改这条记录。`select ... for update` `lock in share mode` `insert/delete/update`
行记录的隐藏列:
- db_row_id:行id,用于生成默认的聚集索引
- db_trx_id:事务id,最后一个对数据操作的事务ID
- db_roll_pt:回滚指针,执行该记录的Undo log信息。
### 隔离级别
#### 类型
| 隔离级别 | 回滚覆盖 | 脏读 | 不可重复读 | 提交覆盖 | 幻读 |
| ---- | ---- | ---- | ----- | ---- | ---- |
| 读未提交 | X | 可能发生 | 可能发生 | 可能发生 | 可能发生 |
| 读已提交 | X | X | 可能发生 | 可能发生 | 可能发生 |
| 可重复度 | X | X | X | X | 可能发生 |
| 串行化 | X | X | X | X | X |
- 读未提交
Read Uncommitted。可能读取到其他事务中未提交的数据,**导致脏读**
- 读已提交
Read Committed。只能读取到其他事务中已提交的数据;**解决脏读**;但可能一个事务中多次查询结果不一致,**导致不可重复读**
- 可重复读(mysql默认级别)
Repeatable Read。**解决不可重复读**;**可能导致幻读**,即读取到额外的数据行。
- 串行化
强制事务排序,**解决幻读**;可能导致大量超时和锁竞争,效率最低
#### 控制
`show variables like 'tx_isolation';`
`select @@tx_isolation`
```
// 设置
set tx_isolation='READ-UNCOMMITTED';
set tx_isolation='READ-COMMITTED';
set tx_isolation='REPEATABLE-READ';
set tx_isolation='SERIALIZABLE';
```
### 锁机制
#### 锁分类
| | 行锁 | 表锁 | 页锁 |
| ------ | ---- | ---- | ---- |
| MyISAM | | √ | |
| BDB | | √ | √ |
| InnoDB | √ | √ | |
| 操作类型 | 描述 |
| ------- | ---------------------------------------- |
| S锁-读锁 | 共享锁,针对同一份数据,多个读操作可以同时进行而不会互相影响。
事务A对记录添加了S锁,可以对记录进行读操作,不能做修改,其他事务可以对该记录追加S锁,但是不能追加X锁,需要追加X锁,需要等记录的S锁全部释放。 |
| X锁-写锁 | 排他锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
事务A对记录添加了X锁,可以对记录进行读和修改操作,其他事务不能对记录做读和修改操作。 |
| IS锁、IX锁 | 意向读锁、意向写锁,属于表级锁,S和X主要针对行级锁。在对表记录添加S或X锁之前,会先对表添加IS或IX锁 |
| | 描述 |
| ---- | ---------------------------------------- |
| 乐观锁 | 一般的实现方式是对记录数据版本进行比对,在数据更新提交的时候才会进行冲突检测,如果发现冲突了,则提示错误信息 |
| 悲观锁 | 在对一条数据修改的时候,为了避免同时被其他人修改,在修改数据之前先锁定,再修改的控制方式。共享锁和排他锁是悲观锁的不同实现,但都属于悲观锁范畴 |
#### 锁原理
InnoDB行锁是通过对索引数据页上的记录加锁实现的
| 算法 | 描述 |
| -------------- | ---------------------------------------- |
| RecordLock锁 | 锁定单个行记录的锁。(记录锁,RC、RR隔离级别都支持) |
| GapLock锁 | 间隙锁,锁定索引记录间隙,确保索引记录的间隙不变。(范围锁,RR隔离级别支持) |
| Next-key Lock锁 | 记录锁和间隙锁组合,同时锁住数据,并且锁住数据前后范围。(记录锁+范围锁,RR隔离级别支持) |
#### 悲观锁
#### 乐观锁
#### 死锁与解决方案
## 集群架构
### 架构设计
- 可用性-冗余
双主+主从模式
- 站点高可用,冗余站点
- 服务高可用,冗余服务
- 数据高可用,冗余数据
- 扩展性
- 提高读性能:加从库,分库分表
- 提高写性能:分库分表
- 一致性
- 不适应从库
- 增加访问路由层
### 主从模式
用途
- 实时灾备,用于故障切换-高可用
- 读写分离,提高查询服务-读扩展
- 数据备份,避免影响业务-高可用
部署条件
- 从库服务器能联通主库
- 主库开启binlog日志(设置log-bin参数)
- 主从server-id不同
#### 实现原理

三个步骤:
1. 主库将数据库变更的操作记录到binlog日志文件中
2. 从库读取主库的binlog文件,写入到从库的relay log中继日志中
3. 从库读取中继日志信息,在从库中进行replay,更新从库数据信息
涉及线程:
1. master服务器对数据库更改操作记录在binlog中,binlog dump thread街道写入请求后,读取binlog信息推送给slave的I/O thread。
2. slave的I/O thread将读取到的binlog信息写入到本地relay log中
3. slave的sql thread检测到relay log的变更请求,解析relay log中内容在从库上执行
主从复制存在的问题:
- 主库宕机,数据可能丢失 -> 半同步复制
- 从库只有一个SQL Thread,主库写压力大,复制很可能延时 -> 并行复制
半同步复制:
- 传统主从复制
- 半同步
- 增强半同步
#### 并行复制
5.6版本后追加并行复制功能,enhanced multi-threaded slave-MTS
### 双主模式
### 分库分表