1. MySQL基本架构
连接器
客户端每发起一个连接请求,首先经过连接器,建立tcp连接,校验账号密码。连接器会维护连接列表processlist 可以通过show processlist
查看,其中刚开启的线程处于sleep状态
Time代表已Sleep的时间,如果超过了wait_timeout需要重连,默认8小时,可以通过show variables like '%timeout%'
命令查看
为了防止断线重连,可以采用如下方法:
- 长连接:由于连接在内存中,容易造成OOM异常,mysql重启,jvm会Full GC
- 重置连接资源:通过命令mysql_reset_connection,可以在不断线的情况下重置连接资源
ps: 要注意让spring配置连接池bean的时候设置的maxIdleTime属性(不同连接池属性名可能不一样)要小于mysql的wait_timeout
缓存
k-v形式,如果命中,直接返回数据,如果未命中,走分析器,并在获取结果后缓存,以便第二次查。因为用的少(缓存都走redis了)8.0后取消了,8.0之前,explain索引分析的时候记得加上SQL_NO_CACHE关掉
分析器
词法分析(查询还是别的操作,哪张表,哪列等),语法分析(运行时会报SQL syntax语法错误)
优化器
是否使用索引,使用什么索引。有时候会用错索引,使用analyze table table_name或者强制走索引force index
执行器
操作引擎执行SQL
引擎
参考
https://baijiahao.baidu.com/s?id=1655327558614401593&wfr=spider&for=pc
通过show engines;
就可以查看支持的引擎,有9种,常见的有3,4种(InnoDB,MyISAM,CSV,MEMORY)
查看某张表的引擎等信息可以用show table status like ‘user’ \G
一张表横向对比
InnoDB
- MySQL默认的事务型引擎
- 用来处理大量短期事务,短期事务大部分是正常提交的,很少回滚
- 通过间隙锁(next-key locking)防止幻读的出现
- 基于聚簇索引建立,与其他存储引擎有很大的区别,聚簇索引对主键查询有很高的性能,不过它的二级索引(secondary index,非主键索引)必须包含主键列。所以如果主键列很大的话,索引会很大
- 性能高
- 自动崩溃恢复
InnoDB页结构,16kb
索引B+树中⼀个节点为⼀⻚或⻚的倍数最为合适,如果读取1.2页也要读取2页
MyISAM
5.1之前,MyISAM是默认的引擎
适用于些只读数据,或者表空间较小
特性:全文索引、支持压缩、空间函数。全文索引:基于分词创建的索引,也可以支持复杂的查询。压缩:如果数据在写入后不会修改,那么这个表适合MyISAM压缩表。可以使用myisampack对MyISAM表进行打包,压缩表是不可以修改数据的,可以减少磁盘IO,提升性能,压缩表也支持索引,但是索引也是只读的
不支持事务和行级锁(后续版本中支持了事务),对整个表加锁,而不是行锁,读取的时候对表加共享锁,写入的时候加排他锁,但是可以同时读写。但是由于没有行锁机制,所以在海量写入的时候,会导致所有查询处于Locked状态。
将表存储在两个文件中:数据文件、索引文件,分别是.MYD、.MYI后缀
行记录数取决于磁盘空间和操作系统中的单个文件最大尺寸
即使是Blob,Text等等长字段,也可以基于前500字符创建索引
可以选择延迟更新索引键,在创建表的时候指定delay_key_write选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是写到缓存区,只有在清理缓存区或者关闭表的时候才会将索引写入磁盘。这可以极大的提升写入性能,但是在主机崩溃时会造成索引损坏,需要执行修复操作。
CSV
- CSV引擎可以将普通的CSV文件作为MySQL表来处理
- 不支持索引
- CSV可以在数据库运行时拷贝或者拷出文件,可以将Excel等电子表格中的数据存储为CSV文件,然后复制到MySQL中,就能在MySQL中打开使用。
- 同样,如果将数据写入到一个CSV引擎表,其他外部程序也可以从表的数据文件中读取CSV的数据。因此CSV可以作为数据交换机制。非常好用。
Memory
所有的数据都保存在内存中,不需要进行磁盘I/O
Memory表的结构在重启以后还会保留,但数据会丢失
需要快速地访问数据,并且这些数据不会被修改(例如将邮编和州名映射的表)
比MyISAM表要快一个数量级(因为在内存中)
2. MySQL索引和SQL调优
关于索引,内容比较多,另外开了一篇文章==>mysql索引
3. 日志系统
3.1 redo log
内容:记录数据修改操作(事务尚未提交)
作用:异常宕机或者介质故障后的数据恢复(crash safe)
层级:innoDB层面
解释:
更新语句–>写redo log–>更新内存数据–>空闲/按策略将redo log写入磁盘,这种先写日志再写磁盘的技术称为WAL(Write Ahead logging)
redo log大小是固定的,循环写。write pos走在前面,表示当前写入redo log的位置。checkpoint表示同步到磁盘的位置。如下图
有一条update语句执行,redo log从write pos开始往右写,到头后循环到最左边继续,当碰到check point说明redo log满了,会立即同步到磁盘。
同样的,如果空闲了也会同步到磁盘,checkpoint也会往右移,当碰到write pos说明redo log空了。
3.2 undo log
内容:记录事务开始前的值
作用:用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
层级:innoDB层面
3.3 bin log
内容:记录二进制
作用:主从复制同步,时间点还原
层级:MySQL Server层面
3. 事务、隔离级别和MVCC
事务
- 原子性(Atomicity):一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,发生错误会被回滚(Rollback)到事务开始前的状态。
- 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则。比如转账一边-100另一边+100,总体不变就是其中一种预设规则。
- 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
隔离级别
几种隔离级别
读未提交(READ UNCOMMITTED) :⼀个事务还没提交时,它做的变更就能被别的事务看到。
读提交(READ COMMITTED) :⼀个事务提交之后,它做的变更才会被其他事务看到。
可重复读(REPEATABLE READ):⼀个事务执⾏过程中看到的数据,总是跟这个事务在启动时看到的数据是⼀致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化(SERIALIZABLE):对于同⼀行记录,“写”会加“写锁”,“读”会加“读锁”,当出现读写锁冲突的时候,后访问的事务必须等前⼀个事务执⾏完成,才能继续执行。
通过以下mysql语句更改
1 | SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 上面几种level; |
并发问题
- 脏读(dirty read) :如果⼀个事务读到了另⼀个未提交事务修改过的数据。
- 不可重复读(non-repeatable read):如果⼀个事务只能读到另⼀个已经提交的事务修改过的数据,并且其他事务每对该数据进⾏⼀次修改并提交后,该事务都能查询得到最新值。
- 幻读(phantom read):如果⼀个事务先根据某些条件查询出⼀些记录,之后另⼀个事务⼜向表中插⼊了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另⼀个事务插⼊的记录也读出来。
ps:不可重复读和幻读有点像,主要区别在于不可重复读是两次查询某一条数据的修改,幻读是查询整张表出现的新增。也就是新增那行原来不存在所以锁不住,控制的手段也会不一样。
对应解决
读未提交:啥都不能解决
读提交:解决脏读,事务A读取的是事务B开始前和提交后的数据
可重复读:解决脏读、不可重复读,事务A整个过程读取的都是事务B开始前的数据
串行化:解决脏读、不可重复读、幻读,事务A过程中事务B只能等待
MVCC
读提交和可重复读为什么可以读取另一个事务开始前的数据呢?这里就要提到MVCC(Multi-Version Concurrency Control ,多版本并发控制),在事务在启动的时候就“拍了个快照”,这个快照被称为一致性视图。
那快照是怎么实现的呢?当然不需要完全复制一张表,而是使用了undo log中一个叫版本链的东西,事实上每一行数据都有隐藏的trx_id记录了每一个版本,还有一个roll_pointer指针域指向旧版本,形成一个undo log链表
MVCC就是根据某一个版本生成对应的一致性视图
如果是读提交,则在每个SQL执行前生成
如果是可重复读,则只在第一次查询的时候生成一次
参考
本文参考
三太子敖丙公众号MySQL系列文章
CSDN博客:二十六画生的博客(https://blog.csdn.net/u010002184/article/details/88526708)
CSDN博客:cwjokaka(https://blog.csdn.net/u013295276/article/details/79105163)