日常提交
This commit is contained in:
6
mysql/mysql底层/binlog.md
Normal file
6
mysql/mysql底层/binlog.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# binlog 日志
|
||||
* ## binlog(二进制日志)
|
||||
* 定义:binlog日志文件也称之为变更日志文件,记录了数据库记录的所有DDL、DML等数据库更新事件的语句,但是不包括任何没有更新数据的语句。
|
||||
* 用途:
|
||||
* 数据恢复:如果mysql数据库进程意外停止,可以通过binlog中的记录来恢复数据库中的数据
|
||||
* 数据复制:可以通过binlog来实现mysql数据库的主从一致
|
||||
49
mysql/mysql底层/mvcc.md
Normal file
49
mysql/mysql底层/mvcc.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 多版本并发控制
|
||||
* ## 多版本并发控制解决的问题:
|
||||
* 在多个事务并发访问资源时,可能会发生并发安全问题。为了解决多个事务同时对资进行读写的问题,可以采用如下解决方案:
|
||||
* 多事务同时对资源进行读取:并发安全
|
||||
* 多事务同时对资源进行写操作:非并发安全,可以对写操作进行加锁来解决并发安全问题
|
||||
* 多事务同时对资源进行读和写操作:非并发安全
|
||||
1. 对读操作和写操作都加锁:性能较差
|
||||
2. 通过MVCC机制来解决并发读写的问题,对写操作加锁,并用MVCC机制来使读操作读到先前的值
|
||||
* ## 多版本并发控的概念:
|
||||
* MVCC通过数据库行的多个版本管理来实现数据库的并发控制。当一个写事务正在更新数据行的值时,通过MVCC机制,可以在另一个事物对数据行进行读操作时读取到被写事务更新之前的值。
|
||||
* 通过MVCC机制,可以更好的解决事务在读-写操作同时发生时的性能问题。MVCC可以避免在写事务时另一个读事务必须等待当前写事务释放排他锁,而是可以通过MVCC读取资源被写事务修改之前的值。
|
||||
|
||||
* ## mysql中读操作的种类:
|
||||
* 当前读:读取数据库中当前的值,为了解决并发安全问题,需要对读操作进行加锁操作,可以尝试加排他锁或者共享锁,当当前事务对资源进行写操作时,读事务会阻塞直到写事务释放锁:
|
||||
```mysql
|
||||
# 为select语句加上共享锁
|
||||
select * from user where... lock in share mode
|
||||
|
||||
# 为select语句加上排他锁
|
||||
select * from user where... for update
|
||||
```
|
||||
* 快照读:mysql中默认select语句的读取方式,当当前事务对资源进行读操作时,如果另一个事务正在对资源进行写操作,那么读操作并不会阻塞而是会读取资源被写事务修改之前的值
|
||||
|
||||
* ## MVCC原理
|
||||
* 隐藏字段:对于使用innodb存储引擎的表,其聚簇索引包含两个隐藏字段:
|
||||
1. trx_id:每个事务对每条记录进行更改时,该trx_id字段都会记载最后一次修改该行记录的事务id
|
||||
2. roll_pointer:指向undo log中关于修改该条数据的记录
|
||||
* ReadView:ReadView是MVCC机制中事务对数据进行快照读时产生的一个读视图。
|
||||
* ReadView原理:
|
||||
* 当事务开启时,会产生当前数据库系统的一个快照,innodb为每个事务构造了一个数组,用来维护当前系统中活跃事务的ID(活跃事务为当前开启了但是尚未提交的事务id)
|
||||
* ReadView中保存了如下信息:
|
||||
* creator_trx_id:创建当前ReadView的事务id
|
||||
* trx_ids:记录创建失误时当前mysql系统中活跃的事务id集合(已经开始但是还没有被提交的事务id)
|
||||
* up_limit_id:trx_ids中最小的事务id
|
||||
* low_limit_id:表示生成ReadView中当前系统应该分配给下一个事务的id
|
||||
* MVCC仅针对读已提交和可重复读的情况,在读已提交的情况下,事务中每执行一次select操作,ReadView都会重复生成;而在可重复读的隔离级别下,事务仅仅会在第一次select操作时生成ReadView
|
||||
* MVCC细节:
|
||||
* 当select语句想要对一条记录中的数据进行读取时,首先会查看记录的trx_id是是否对当前事务的读操作是可见的,判断事务是否可见的标准如下所示:
|
||||
* 如果记录的trx_id大于low_limit_id,那么说明在创建ReadView时对记录进行修改的事务还没有被创建,当然修改对当前读事务来说是不可见的
|
||||
* 如果trx_id小于up_limit_id,那么说明对该记录进行修改的事务id小于创建ReadView时最小的活跃事务id,在创建ReadView时修改记录的事物已经被提交,修改对当前事务来说可见
|
||||
* 如果trx_id位于up_limit_id和low_limit_id之间,那么:
|
||||
* trx_id如果与trx_ids中保存的某个活跃事务id相同,那么说明在创建ReadView时修改事务的id尚未被提交,修改对当前失误不可见
|
||||
* 如果trx_id与trx_ids中每个活跃事物id都不相同,那么修改事务在创建ReadView事物之时已经被提交,修改对当前事务可见
|
||||
* 根据上述规则,如果想要读取的记录trx_id对当前事务来说可见,那么获取该事务id所对应的数据值;如果trx_id对当前ReadView来说不可见,那么沿着roll_pointer沿着undo log向前寻找,知道找到对当前ReadView可见的事务id;如果undo log中所有的事务id对当前ReadView来说都不可见,那么对当前事物来说数据表中该条记录并不可见
|
||||
|
||||
* ## MVCC与幻读问题
|
||||
* MVCC仅在读已提交和可重复读的情况下起作用,而关于幻读问题,MVCC仅在可重复读的隔离级别下解决。
|
||||
* 在可重复读的隔离级别下,ReadView仅仅在第一次select语句时生成,故而在同一事务中多次读取之间,其他事务插入了新数据,那么该新数据对应的trx_id在readView创建时应该处于活跃或者未创建的状态,故而对ReadView所对应事物来说,即使其他事务插入了新数据,那么新插入的数据也不可见。
|
||||
* 而在读已提交的隔离级别下,ReadView在每次读操作的情况下都会被创建,故而在两次读操作之间,如果新的数据被插入,那么新插入的数据对后一次读操作创建的ReadView来说是已经提交的数据,是可见的。故而MVCC在读已提交的隔离级别下并不能够解决幻读的问题。
|
||||
64
mysql/mysql底层/mysql加锁.md
Normal file
64
mysql/mysql底层/mysql加锁.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# mysql锁
|
||||
* ## msyql中锁的分类
|
||||
* 从数据库操作的类型划分,mysql中的锁可以分为读锁/共享锁和写锁/排他锁
|
||||
* 读锁(S锁,Share)
|
||||
* 写锁(X锁,Exclusive)
|
||||
* 写锁和读锁示例
|
||||
```mysql
|
||||
# 为语句加上写锁
|
||||
select * from table_name for udpate
|
||||
|
||||
# 为查询语句加上读锁
|
||||
select * from table_name lock in share mode
|
||||
# or
|
||||
select * from table_name for share(mysql 8.0新增语法)
|
||||
```
|
||||
* 在获取读锁或者写锁之后,只有当事务结束之后,获取到的读锁或者写锁才会被释放。在innodb中,for update或者for share语句只会为查询匹配的行数据上锁,并且,当事务结束或者回滚之后,会释放为数据行所加的排他锁或者共享锁
|
||||
* 在对mysql中数据进行写操作(UPDATE、INSERT、DELETE)时,会通过如下方式加锁:
|
||||
* DELETE操作:对mysql表中数据执行DELETE操作,需要为要删除数据添加排他锁(X锁)
|
||||
* UPDATE操作:对mysql表中数据执行UPDATE操作分如下情况:
|
||||
* update操作不改变记录的键值,且更新的列在更新前后占用的空间未发生变化:
|
||||
* 此时会在B+数中定位到该条记录,并且为该条记录添加X锁,在修改完成之后释放X锁
|
||||
* update操作没有修改键值,但是更新前后该条记录的某一列占用空间发生了变化:
|
||||
* 此时,会先对原先的记录加上X锁,并进行DELETE操作,并且在DELETE操作后,通过INSERT操作并添加隐式锁来插入修改后的数据
|
||||
* update操作修改了键值:
|
||||
* 同样,也会通过先DELETE再INSERT的操作来更新数据
|
||||
* INSERT操作:通过添加隐式锁的操作来保证mysql中多事务的并发安全
|
||||
* 从mysql数据库的粒度来对锁进行划分
|
||||
* 表锁:
|
||||
* 表级锁会锁住mysql中的整张表,其粒度较大,受其影响并发性能较低
|
||||
* 表级锁是mysql中最基本的加锁策略,并不依赖于存储引擎,不管是innodb还是myisam都支持表级锁
|
||||
* 表级锁的使用场景:
|
||||
* 通过的select或者update、delete、insert操作innodb并不会加表级锁,但是对于alter table、drop table这类ddl语句对表的结构进行修改时,需要对其表的元数据进行加锁(MDL),对元数据加锁的过程中,想要对该表中数据进行select、delete、update、insert的操作会被阻塞
|
||||
* 对表锁进行加锁的语句:
|
||||
```mysql
|
||||
# 对表锁进行加锁
|
||||
# 在对表进行上锁操作后,无法再去读取其他未上锁的表
|
||||
lock tables table_name read/write
|
||||
|
||||
# 对上锁的表进行释放操作
|
||||
unlock tables;
|
||||
```
|
||||
* 对于myisam存储引擎,读操作之前会为涉及到的表加上读锁,并且在读操作执行完成之后释放上锁的表;而对于写操作,myisam存储引擎会在写操作执行之前为涉及到的表加上写锁。反之,innodb存储引擎在对数据进行查找和修改时不会在表级别加锁,而是会在更细的粒度上为行数据进行加锁,以此来提高程序的并发性能。
|
||||
* 元数据锁(MDL):对于表结构的修改(DDL操作),会对其元数据锁进行加锁,而对于该表的增删改操作,则是会默认加上元数据的读锁。故而在对表结构进行修改时,想要对表中数据进行増删改操作需要获取其元数据的读锁,此时对表数据的増删改操作会被阻塞。
|
||||
* 意向锁:意向锁通常用来简化行级锁和表级锁是否兼容的判断操作。如果为一个表中某条数据加上行级锁,那么innodb存储引擎会自动的为该行记录所在的页和表加上页级和表级的意向锁,那么当接下来有事务想要对该表进行表级加锁操作时,就无需查看该表中所有数据来判断是否存在表中数据的锁和表级锁冲突。只需判断该表的意向锁和想要加上的表级锁是否冲突即可。
|
||||
* 行锁
|
||||
* 相对与表锁,行锁的粒度更小,故而其并发度更高,并发性能更好。但是行锁可能会造成死锁问题,加锁的开销也更大。
|
||||
* 是否支持行锁取决与存储引擎,比如myisam不支持行锁但是innodb却支持行锁
|
||||
* 行锁种类:
|
||||
* 记录锁:记录锁针对于单条记录,在一个事物中,如果存在update、delete等修改操作,其默认会获得想要修改的那条记录的记录锁,并且在执行修改操作之后才会被释放。若一个事务中对某条记录调用update操作,那么直到当前事务提交或者回滚前,若其他事务想要修改同一行记录,会进入阻塞状态,知道持有记录写锁的退出才能继续执行。
|
||||
* 间隙锁:间隙锁对记录的范围进行加锁。间隙锁是不冲突的,多个事务可以同时持有某一个范围的间隙锁。用间隙锁或者mvcc机制都能够解决死锁问题。但是间隙锁可能会导致死锁问题,如果多个事务各自持有自己范围的间隙锁,并同时向对方持有间隙锁的范围插入数据,此时两个事务都会等待对方释放间隙锁,在这种情况下会发生死锁问题。
|
||||
* 临键锁(next-key lock):在锁住某条记录的同时也锁定某个范围内的数据,使之无法被其他事务插入数据
|
||||
* 页锁:在页面的粒度上进行上锁
|
||||
* 在粒度上,不同层级的所的数量是有上限的,例如innodb,其优先会选用行锁来进行加锁。当行锁数量过多,占用空间超过表空间上限时,会进行锁升级的行为。行锁会升级为页面锁,此时锁的粒度会增加,锁花费的开销也会变小,但是粒度变大后并发性能也会变低。
|
||||
* 通过对待锁的方式进行划分
|
||||
* 乐观锁:乐观锁假设每次对数据进行修改时,其他事务不会访问数据,故而不会对数据正真的加锁,只是会在修改时检查数据是否被其他事务修改过。
|
||||
* 乐观锁的实现方式:
|
||||
* cas
|
||||
* 版本号机制
|
||||
* 悲观锁:
|
||||
* 悲观锁假设一个事务在对数据进行修改时,其他事务也会对数据进行修改,故而在每次修改数据时都会对要修改的数据进行加锁,悲观锁是通过mysql内部提供的锁机制来实现的
|
||||
* 通过加锁方式进行划分:
|
||||
* 隐式锁:隐式锁通常用于插入操作。在某一个事务在对所记录进行插入操作时,如果其他事务想要访问该条记录,会查看最后修改该条记录的事务id是否是活跃的事务,如果是活跃事务,那么其会帮助插入事务创建一个X锁并且让自己进入阻塞状态。
|
||||
* 隐式锁是一种延迟加锁的机制,只有当有其他事务想要访问未提交事务插入的记录时,隐式锁才会被创建。该机制能够有效减少创建锁的数量。
|
||||
* 显示锁:可以通过命令查看到的锁,通常会用for update、lock in share mode 或者 update、delete操作会生成显示锁
|
||||
5
mysql/mysql底层/redo log & undo log.md
Normal file
5
mysql/mysql底层/redo log & undo log.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# redo log & undo log
|
||||
* ## undo log
|
||||
* undo log通常用于事务的回滚操作,用来保证事务的原子性。
|
||||
* 每当发生数据修改操作时(update、insert、delete),关于当前修改操作的相反操作会被记录到undo log中,通常用于在回滚时将数据回复到修改之前的值。
|
||||
* undo log默认被记录到mysql的表空间中,因而对undo log进行追加时,对表中页数据进行修改时也会产生redo log,对undo log的追加会通过fsync操作持久化到redo log中。这样即使在一个事务尚未被提交或是回滚之前,mysql服务器崩溃,下次重启时,也可以通过redo log恢复对数据的修改和undo log的内容,回滚事务时也能将数据恢复到崩溃前尚未被事务修改的状态。
|
||||
24
mysql/mysql底层/索引.md
Normal file
24
mysql/mysql底层/索引.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# mysql索引
|
||||
* ## mysql索引的分类
|
||||
* 从功能逻辑上对索引进行分类:
|
||||
* 普通索引:只是用于提升查询效率,没有任何的附加约束
|
||||
* 唯一性索引:通过unique关键字可以设定唯一性索引,其会限制该索引值必须是唯一的,但是允许为null
|
||||
* 主键索引:特殊的唯一性索引,在唯一性索引的基础上,主键索引还增加了不为空的约束
|
||||
* 单列索引:作用在一个字段上的索引
|
||||
* 联合索引:作用于多个字段上的索引
|
||||
* ## 索引的创建、删除操作
|
||||
```mysql
|
||||
# 索引的创建方式
|
||||
alter table table_name add [unique/index] idx_name (col_name...)
|
||||
# or
|
||||
create [unique/index] on table_name(col_name...)
|
||||
|
||||
# 索引的删除方式
|
||||
alter table table_name drop index idx_name
|
||||
# or
|
||||
drop index idx_name on table_name
|
||||
```
|
||||
* ## 索引的可见性
|
||||
```mysql
|
||||
# 通过修改索引的可见性,可以比较创建
|
||||
```
|
||||
Reference in New Issue
Block a user