mysql学习笔记图
2022-03-17 11:04:17 0 举报
AI智能生成
MySQL作为后端开发最常用的数据库,了解其底层的实现原理,对于平时的问题排查和数据库优化有着很大的帮助,所以特意花时间整理了MySQL底层的核心知识点。
作者其他创作
大纲/内容
buffer pool缓冲区
描述:MySQL查询时,以页为单位从磁盘读出来放到这个区域
free链表
描述:将128M的buffer pool按照每页16kb生成的一个空闲链表,
链表的每页通过指针指向buffer pool的空闲页,当有数据查到对应的buffer pool,
对应的空闲链表就会删除
链表的每页通过指针指向buffer pool的空闲页,当有数据查到对应的buffer pool,
对应的空闲链表就会删除
头结点:链表的个数,最大个数128M/16KB
lru淘汰链表
每次查询数据时,存到buffer pool的同时,也存到lru链表,
当buffer pool满了,通过lru中最近最少使用淘汰数据,淘汰链表最后的数据
当buffer pool满了,通过lru中最近最少使用淘汰数据,淘汰链表最后的数据
前5/8热点数据:经常使用的数据,页的第一次查询与第二次查询大于1秒的数据
前面1/4部分不用向前移动数据页
后面3/4需要向前移动数据页
后3/8冷数据:不经常使用的数据
头结点:链表的个数
flush脏页链表
当buffer poll的数据页被更新后,这页的数据放入这个缓存区域
mysql后台有个定时任务到这个链表的脏页数据持久化
日志系统
redolog日志
产生原因:如果并发很多,多个事务执行,每个事务都去修改buffer pool,每个事务对应的脏页都要去持久化,但是数据在磁盘的零散的,到处移动性能很差,速度慢,通过redolog存日志可以顺序IO执行,暂时不用去持久化,保证数据不丢失
innodb存储引擎拥有的回滚日志,数据页中的每个sql数据更新都会生成一个redolog,事务提交的时候才去持久化
logbuffer缓冲区
每个sql语句都会生成一个redolog对象,这个对象都存入到这个缓存区,然后进行持久化
持久化策略(innodb_flush_log_at_trx_commit)
0:事务提交时,不立即对redolg持久化,这个任务交给后台线程去做
1:事务提交时,立即进行持久化
2:事务提交时,将redolog立即写入操作系统缓存区,不立即进行持久化
如何保证数据不丢:重启mysql时会去读取redolog日志,然后配合之前的老数据去恢复,恢复之后放入buffer pool,然后等待后台定时任务去执行持久化
两个日志文件:磁盘对应两个48M的磁盘区域,redolog最终都顺序IO持久化到这个空间
checkpoint:如果磁盘满了,又有日志进来,就不等后台定时任务去持久化脏页了,
现在就立刻去执行,然后删除之前的日志,存最新的日志
现在就立刻去执行,然后删除之前的日志,存最新的日志
改大这两个文件:mysql在运行期间可以存更多的redolog,那么checkpoint的出现时间就会最晚,
脏页数据持久化也就没那么着急了,减少后台线程的压力;缺点就是启动的时候比较慢,需要去加载这两个文件恢复数据
脏页数据持久化也就没那么着急了,减少后台线程的压力;缺点就是启动的时候比较慢,需要去加载这两个文件恢复数据
binlog日志
主要用于主从数据同步
持久化策略sync_binlog
0:表示MySQL不控制binlog的刷新,由操作系统自己去控制缓存刷新
>0:表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去
1:最安全的就是sync_binlog=1了,表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置。
undolog日志
主要用于回滚MVCC视图
事务
隔离级别
Read Uncommitted(读取未提交内容):在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
Read Committed(读取提交内容):个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果
Repeatable Read(可重读):这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
Serializable(可串行化):这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
传播特性
Propagation.REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置
Propagation.REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务
Propagation.SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行
Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
Propagation.MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常
Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
Propagation.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作
MVCC
三个隐藏的列
row_id:行ID,MySQL的B+树索引特性要求每个表必须要有一个主键。如果没有设置的话,会自动寻找第一个不包含NULL的唯一索引列作为主键。如果还是找不到,就会在这个DB_ROW_ID上自动生成一个唯一值,以此来当作主键
trx_id:事务ID,记录的是当前事务在做INSERT或UPDATE语句操作时的事务ID(DELETE语句被当做是UPDATE语句的特殊情况)
roll_pointer:回滚指针,通过它可以将不同的版本串联起来,形成版本链。相当于链表的next指针
核心问题
判断版本链中哪些版本对当前事务可见
版本链访问记录逻辑
MVCC只在读取已提交(Read Committed)和可重复读(Repeatable Read)两个事务级别下有效
ReadView一致性视图
所有未提交事务的ID数组和已经创建的最大事务ID组成,例如:[100,200],300。事务100和200是当前未提交的事务,而事务300是当前创建的最大事务(已经提交了)
读取已提交:每执行一次SELECT语句就会重新生成一份ReadView
可重复读:只会在第一次SELECT语句执行的时候会生成一份,后续的SELECT语句会沿用之前生成的ReadView(即使后面有更新语句的话,也会继续沿用)
版本链(min_id指向ReadView中未提交事务数组中的最小事务ID,而max_id指向ReadView中的已经创建的最大事务ID)
DB_TRX_ID < min_id:这个版本比min_id还小(事务ID是从小往大顺序生成的),说明这个版本在SELECT之前就已经提交了,所以这个数据是可见的
DB_TRX_ID > max_id:表示这个版本是由将来启动的事务来生成的,当前还未开始,那么是不可见的
min_id <= DB_TRX_ID <= max_id
如果这个版本的事务ID在ReadView的未提交事务数组中,表示这个版本是由还未提交的事务生成的,那么就是不可见的
如果这个版本的事务ID不在ReadView的未提交事务数组中,表示这个版本是已经提交了的事务生成的,那么是可见的
undolog
insert:事务提交后立即删除
update:需要支持MVCC,不会立即删除
change buffer
唯一索引需要判断唯一性,所以用不上
如果数据不再内存中,则缓存到内存,更新内存的数据,然后放入change buffer中,等下次查询时merge到磁盘
写多读少的场景收益最大,如果写了马上伴随着读,还要去merge,效率就很低
delete:记录打删除标记(逻辑删除)
锁
分类
共享锁(S锁):假设事务T1对数据A加上共享锁,那么事务T2可以读数据A,不能修改数据A;lock in share mode
排他锁(X锁): 假设事务T1对数据A加上排他锁,那么事务T2不能读数据A,不能修改数据A;for update
意向共享锁(IS锁): 一个事务在获取(任何一行/或者全表)S锁之前,一定会先在所在的表上加IS锁
意向排他锁(IX锁): 一个事务在获取(任何一行/或者全表)X锁之前,一定会先在所在的表上加IX锁
意向锁的作用:假设事务T1,用X锁来锁住了表上的几条记录,那么此时表上存在IX锁,即意向排他锁。那么此时事务T2要进行LOCK TABLE … WRITE的表级别锁的请求,可以直接根据意向锁是否存在而判断是否有锁冲突
加锁算法
Record Locks:该锁是对索引记录进行加锁!锁是加在索引上而不是行上的。注意了,innodb一定存在聚簇索引,因此行锁最终都会落到聚簇索引上
Gap Locks:间隙锁,是对索引的间隙加锁,其目的只有一个,防止其他事物插入数据
何时生效
当隔离级别为Repeatable Read和Serializable时,就会存在间隙锁
隔离级别比Read Committed低的情况下,也不会使用间隙锁,如隔离级别为Read Uncommited时,也不存在间隙锁
Next-Key Locks:Record Lock+Gap Lock,锁住的是索引前面的间隙,实现锁表的操作
何时用表级锁
只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
只在RR和Serializable中是成立的。如果隔离级别为RU和RC,无论条件列上是否有索引,都不会锁表,只锁行
死锁
两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁
互相等待的进程称为死锁进程
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB
mysql自带的策略
直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置,默认时间50秒太长,如果太短会误判
发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑
人为的解决办法
终止(或撤销)进程。终止(或撤销)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态中解除出来
show processlist;
kill 12345(进程Id);
抢占资源。从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以打破死锁状态
表锁
lock table read/write
MDL(metadata lock)
mysql5.5自动添加,读锁不影响,写锁互斥
多个事务之前操作,如果查询的时候修改字段会让线程池饱满
mysql的infomation_schema库的innodb_trx表找到对应长事务kill掉
alter table里面设置等待时间
myisan引擎不支持表级锁
全局锁
全库备份时使用
索引
数据结构划分
B+树索引
索引的查询步骤
索引的选择
判断索引是否失效
对建立索引的列等号左边进行算术运算
范围查询时,查询的列表接近全表扫描,这时候会选择全表扫描,减少索引回表次数
联合索引不遵从最左前缀原则
查询的数据值进行了隐形转换,比如mysql中的字符转换为0
or查询左右的字段有没有用索引的
索引条件使用IS NULL或者IS NOT NULII
左侧模糊查询
多个索引优化器选择查询页次数最少的索引
联合索引
最左前缀原则:索引的第一个字段必须存在,不然无法匹配索引树上的页
如何判断索引被用到
判断当前索引列是否被排序
为什么使用B+树
二叉树:按升序递增的数据新增时容易形成链表
红黑树
红黑树的叶子节点和非叶子节点都存储索引和数据
红黑树旋转影响性能
红黑树的树会很高
hash:不支持范围查询
页结构
指针:指向前一页和后一页
索引头:索引数据分组,存每个组中的第一个索引值
数据表:存的这一页的数据项
大小:每一页默认大小16KB左右,指针大小6KB
HASH索引
优点:查询效率高
缺点:不支持范围查询
hash算法:哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针
FULL TEXT索引
物理存储划分
聚族索引
索引和数据存储在一起
非聚族索引
索引和数据分开存储
逻辑角度划分
主键索引
特殊的唯一索引
索引列不允许有空值
唯一索引
索引列必须唯一
允许有空值
单列索引
用表中的某一个字段建立的索引
多列索引
覆盖索引
查询的列属于索引里面存在的列
联合索引
遵循最左前缀原则
主从同步
master一个线程,slave两个线程
binlog dump thread线程
当有数据更新时,master会按照binlog的格式,将更新的数据写到binlog中,然后创建这个线程通知slave有数据更新
I/O thread线程
用于请求master,master会返回当前binlog的名称、当前数据更新的位置、binlog文件副本的位置。然后将binlog保存在relay log(中级日志)中,主要记录数据更新的信息
SQL thread线程:当检测到中继日志有更新,就将更新的内容同步到slava数据库中
策略
同步策略:master等所有的slave都回应后才提交,这个主从同步性能会严重受影响
半同步策略:master至少等待一个slave响应后才提交
异步策略:master不用等待slave响应就提交
延迟策略:slave要落后于master指定的时间
常见的存储引擎
innodb
页作为磁盘和内存的交互单位
5.5版本后,mysql的默认存储引擎
应用场景:事务性,安全性操作较多的情况
myisam
不支持事务
不支持行级锁
不支持外键
应用场景:执行大量的select
比如slave从库
memory
数据存储在内存,表结构存储在磁盘,访问效率高
服务关闭,表中的数据会丢失
慢sql如何排查?
1、分析sql的执行计划,看是否使用索引
2、内存是否足够
3、查询的数据量是否很大,可以分批查询
4、是否查询了不必要的列和行
5、锁或者死锁
6、网诺慢
0 条评论
下一页