索引用来快速的寻找那些具有特定值的记录,如果没有索引,一般来说执行查询时遍历整张表
索引的原理:就是把无序的数据变成有序的查询
(1)把创建了索引的列的内容进行排序
(2)对排序结果生成倒排表
(3)在倒排表内容上拼上数据地址链
(4)在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到数据
都是B+树的数据结构
(1)聚簇索引:将数据存储与索引放到一块,并且是按照一定顺序组织的,找到索引也就找到了数据,
数据的物理存放顺序与索引顺序一致。
(2)非聚簇索引:叶子节点不存储数据,存储的是数据行地址,也就是根据索引查找到数据行的位置
再取磁盘查找数据数据。
(1)查询通过聚簇索引可以直接获取数据,相比于非聚簇索引需要第二次查询(非覆盖索引的情况下)效率要高
(2)聚簇索引对于范围查询的效率很高,因为其数据是按照从小到大的顺序排列的
(3)聚簇索引适合用在排序的场合,非聚簇索引不适合
(1)维护索引很昂贵,特别是插入新行或者主键被更新导致要分页的时候
(2)表如果使用UUID作为主键,使数据存储稀疏,这就会出现聚簇索引有可能比全表扫描更慢,所以建议
使用自增主键
(3)如果主键比较大的话,那辅助索引将会变得更大,因为辅助索引的叶子存储的是主键值;过长的主键值,
会导致非叶子节点占用更多的物理空间
查询更快、占用空间更小
(1)适合索引的列是出现在where子句中的列,或者连接子句中指定的列
(2)基数较小的类,索引效果较差,没有必要建立索引
(3)使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果
搜索词超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配
(4)不要过度索引,索引需要额外的磁盘空间,并降低写操作性能。在修改表内容的时候,索引会进行更新
甚至重构,索引列越多,这个时间就会越长
(5)定义有外键的数据列一定要建立索引
(6)频繁更新的字段不适合创建索引
(7)若是不能有效区分数据的列不适合做索引
(8)尽量地扩展索引,不要新建索引
(9)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引
(10)对于定义为 text image bit 的数据类型的列不要建立索引
基本特性:
(1)原子性:一个事务中的操作要么全部成功,要么全部失败
(2)一致性:数据库总是从一个一致性的状态转换到另外一个一致性的状态
(3)隔离性:一个事务的修改在最终提交之前,对其他事务是不可见的
(4)持久性:一个事务一旦提交,所做的修改就会永久的保存到数据库中
隔离级别:
(1)读未提交:可能会读到其他事务未提交的数据,也叫做脏读
(2)读已提交:解决了脏读,但是没有解决不可重复读,也就是两次读取的结果不一致
(3)可重复读:解决了不可重复读,但是没有解决幻影读。这是mysql的默认隔离级别
(4)串行:一般是不会使用的,因为他会给每行数据都加锁,会导致大量的超时和锁竞争问题
脏读:某个事务已更新一份数据,但是还未提交,另一个事务在此时读取了同一份数据,由于某些原因,
前一个事务进行了RollBack操作,则后一个事务读取到的数据就是不正确的
不可重复读:在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务
更新的原有的数据
(1)mysql的主从复制中主要有三个线程:master(binlog dump thread) master一条线程
slave(I/O thread 、SQL thread) slave两条线程
(2)主节点binlog,主从复制的基础是主库记录数据库的所有变更记录到binlog,binlog是数据库服务器
启动那一刻起,保存所有修改数据库结构或内容的一个文件
(3)主节点 log dump 线程,当binlog有变动时, log dump 线程读取其内容并发送给从节点
(4)从节点I/O线程接收binlog内容,并将其写入到 relay log 文件中
(5)从节点的SQL线程读取 relay log 文件内容对数据更新进行重放,最终保证主从数据库的一致性
(6)主从节点使用 binlog 文件 + position 偏移量来定位主从同步位置,从节点会保存其已接收到的
偏移量,如果从节点发生宕机重启,则会自动从 position 的位置发起同步
MyISAM:
(1)不支持事务,但是每次操作都是原子的
(2)支持表级锁,即每次操作都是对整个表加锁
(3)存储表的总行数
InnoDB:
(1)支持ACID事务,支持事务的四种隔离级别
(2)支持行级锁及外键约束,因此可以支持写并发
(3)不存储总行数
(1)普通索引:允许被索引的数据列包含重复的值
(2)唯一索引:可以保证数据记录的唯一性
(3)主键索引:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录
(4)联合索引:索引可以覆盖多个数据列
(5)全文索引:通过建立倒排索引,可以极大的提升索引效率,解决判断字段是否包含的问题,
是目前搜索引擎使用的一种关键技术
对数据库性能的影响:
(1)索引可以极大的提高数据的查询速度
(2)通过使用索引,可以在查询过程中,使用优化隐藏器,提高系统的性能
(3)但是会降低插入、更新、删除表的速度,因为在执行这些写操作时,还要操作索引文件
索引覆盖就是在一个SQL执行时,可以利用索引来快速查找,并且此SQL所要查询的字段在当前索引对应的字段中都包含了,
那么此SQL走完索引后不用回表了,所需要的字段都在当前索引的叶子节点上存在,可以直接作为结果返回了
(1)当一个SQL想要利用索引时,就一定要提供该索引所对应的字段中最左边的字段,比如针对 a b c 三个
字段建立了一个索引,如果想要走索引的话一定要提供 a 字段
(2)这是因为在建立 a b c 三个字段的联合索引时,底层的B+树是按照 a b c 三个字段从左往右从小到大
排序的,会先根据 a 的大小排序,当 a 相等时才根据 b 排序,以此类推
Innodb通过 Buffer Pool,LogBuffer,Redo Log,Undo Log 来实现事务的,以一个update语句为例:
(1)Innodb在接收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在 buffer Pool 中
(2)执行update语句,修改 Buffer Pool 中的数据,也就是内存中的数据
(3)针对update语句生成一个 Redo Log 对象,并存入 LogBuffer中
(4)针对update语句生成 undo Log 日志,用于事务回滚
(5)如果事务提交,那么则把 Redo Log 对象进行持久化,后续还有其他机制将 Buffer Pool 在中所修改
的数据页持久化到磁盘中
(6)如果事务回滚,则利用 undo Log 日志进行回滚
B树:
(1)按照节点排序
(2)一个节点可以存多个元素,多个元素也排序了
B+树:
(1)拥有B树的特点
(2)叶子节点之间有指针
(3)非叶子节点上的数据在叶子节点上都冗余了,叶子节点中存储了所有的元素,并且排好顺序
为什么使用B+树:
(1)B+树通过对数据进行排序可以提高查询速度
(2)B+树一个节点中可以存储多个元素,从而使B+树的高度不会太高,在mysql中一个Innodb页就是一个
B+树节点,一个Innodb页默认为16KB,所以一把情况下一颗两层的B+树可以存2000万行左右的数据
(3)叶子节点中存储了所有数据并且进行了排序,并且叶子节点之间有指针,可以很好的支持全表扫描,
范围查找等SQL语句
(1)检查是否走了索引,如果没有则优化SQL利用索引
(2)检查所利用的索引是否是最优索引
(3)检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据
(4)检查表中数据是否过多,是否应该进行分库分表了
(1)第一范式:每个表都应该有主键,并且每个字段要求原子性不可再分
(2)第二范式:在第一范式的基础上,所有非主键字段必须完全依赖主键,不能产生部分依赖
(3)第三范式:在第二范式的基础上,所有非主键字段必须直接依赖主键,不能产生传递依赖
设计范式的目的:减少数据冗余
(1)左连接(左外连接):以左表作为基准进行查询,左表数据会全部显示出来,右表如果和左表数据
不匹配则显示为null
(2)右连接(右外连接):以右表作为基准进行查询,右表数据会全部显示出来,左表如果和右表数据
不匹配则显示为null
(3)全连接:先以左表进行左外连接,再以右表进行右外连接
(4)内连接:显示表之间有连接匹配的所有行
(5)笛卡尔积:也叫交叉连接
(1)NOT NULL(非空约束):用于控制字段的内容一定不能为空
(2)UNIQUE(唯一性约束):控制字段内容不能重复,一个表允许有多个Unique约束
(3)PRIMARY KEY(主键约束):用于控制字段内容不能重复,但一个表只允许出现一个
(4)FOREIGN KEY(外键约束):用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,
因为它必须是它指向的那个表中的值之一
(1)原子性:事务是最小的执行单位,不允许分割。整个事务中的所有操作,要么全部完成,要么全部不完成,
不可能停滞在中间某个环节
(2)一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏
(3)隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
(4)持久性:在事务完成以后,该事务对数据库中数据的改变是持久的
事务的隔离级别越高,并发性就越差,性能就越低
(1)读未提交:事务A在事务B未提交前读取数据,如果事务B撤销了修改,那么A会读取到脏数据
(2)读已提交:事务A分别在事务B提交前和提交后读取数据,出现不可重复读
(3)可重复读
(4)序列化
(1)索引最大的好处就是提高查询速度
(2)缺点是更新数据时效率低,因为要同时更新索引
(3)对需要频繁查询的数据建立索引,对需要频繁更改的数据不建议使用索引
(1)数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
(2)数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小
数据库连接数来设定的
(3)数据库连接是一种关键的有限的昂贵的资源,对数据库连接的管理能显著影响到整个应用程序的伸缩性
和健壮性,影响到程序的性能指标
(1)非叶子节点不存储数据,只存储索引(冗余),可以放更多的索引
(2)叶子节点包含所有索引字段
(3)叶子节点用指针连接,提高区间访问的性能
(4)所有的元素节点从左到右依次递增排序
(5)所有索引元素不重复
(1)聚集索引叶子节点包含了完整的数据(InnoDB采用的聚集索引)
(2)非聚集索引:索引文件和数据文件不在一起存储
(1)查找效率高
(2)占用存储空间少
(3)尽量自增的原因:采用非自增插入的时候会效率低
(1)存储的数据先以索引的第一个元素name排序,当name相等时,才以第二个元素age排序,依次类推
(1)B+树叶子节点有双向指针,范围查找效率更高
(2)B树的有的索引在非叶子节点,B+树的所有索引全部在叶子节点,B+树查找效率高
(1)读未提交:有脏读问题(读到某个事务未提交的数据,如果它rollback的话数据就会出现错误)
(2)读已提交:解决了脏读,有不可重复读问题(在同一个事务中可能出现两次读取到的数据不一致)
(3)可重复读:在第一条查询时会将当前数据库这张表的值快照记录下来,之后就会读取这个快照的值,
解决了不可重复读问题,有幻读问题。
会存在用旧的数据去计算,然后更新数据库,会出现问题(并发写覆盖问题),解决:
a.乐观锁:加一个版本号,每次更新后会修改版本号。当某个事务尝试更新数据时会比较当前
版本号与旧的版本号是否一致;如果一致就更新,如果不一致就重试
b.悲观锁:就会使用数据库中最新的记录去更新
(4)串行:加了读锁,阻塞等待其它事务的更新操作,上面问题全部解决,效率低
(1)读锁:读锁是共享的,多个事务可以同时读同一个资源,但不允许其他事务修改
(2)写锁:写锁是排他锁,会阻塞其他的写锁和读锁
(1)可重复读和读已提交底层就是MVCC机制实现的
读已提交:每次读取的是记录版本链中最新的数据
可重复读:在当前事务中,某一时刻读取数据之后,会与那个读取到的记录版本链绑定,之后每次读取都是
读这个记录版本链中的数据。即使后边数据已经在其他事务中被更新了。底层原理是CopyOnWriter
(2)MVCC就是多版本并发控制机制,为了让读写可以同时高并发执行,不用加锁的方式
(3)读的数据是旧的数据,写数据是写最新的数据
(1)查询方法中只有一条查询语句,不需要使用事务
(2)如果有多条查询语句,并且隔离级别是可重复读的,那么需要使用事务。
不开启的话:会查询到最新数据,不复合可重复读的特性了。比如说统计报表的话,需要统计同一时刻的数据,
但是不开启事务的话,查询出来的数据的时间点可能会出现不同。
(1)对性能要求更高的话,使用读已提交隔离级别
(2)对数据一致性要求高的话,使用可重复读隔离级别
(1)原子性:当前事务的操作,要么同时成功,要么同时失败。原子性由 undo log 日志来保证
(2)一致性:使用事务的最终目的,由业务代码正确逻辑保证
(3)隔离性:在事务并发执行时,他们内部的操作不能互相干扰
(4)持久性:一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由 redo log 日志来保证
(1)并发情况下,数据库连接池容易被撑爆
(2)锁定太多的数据,造成大量的阻塞和锁超时
(3)执行时间长,容易造成主从延迟
(4)回滚所需要的时间比较长
(5)undo log 膨胀
(6)容易导致死锁
(1)将查询等数据准备操作放到事务外
(2)事务中避免远程调用,远程调用要设置超时,防止事务等待时间太久
(3)事务中避免一次性处理太多数据,可以拆分成多个事务分次处理
(4)更新等涉及加锁的操作尽可能放在事务靠后的位置
(5)能异步处理的尽量异步处理
(1)传统数据无法支撑高并发互联网业务场景,海量数据下查询数据慢,所以需要分库分表
(2)垂直分片:从业务维度切分扩展数据库连接数,提升数据库IO性能
(3)水平分片:从数据维度切分扩展单表可控数据量,提升数据库查询性能。水平分片从理论上突破了单机
处理数据量处理的瓶颈,并且扩展相对自由,是分库分表的标准解决方案
常用分库分表策略:
(1)取模分片 优点:数据存放均匀 缺点:扩容需要大量数据迁移
(2)按范围分片 优点:扩容不需要迁移数据 缺点:数据存放不均匀,容易产生数据倾斜
(1)查数据时,每次从磁盘取一页的数据放入内存(mysql默认页大小为16KB),这样的话可以减少磁盘IO
提升性能
(2)从磁盘取一页的数据时,会根据主键给数据排序,这样的话查询数据比较快
(3)页目录:每个目录项存储每一组数据中最小的主键值 可以提升查询效率
(1)存储引擎是基于表的,而不是基于库的,创建表的时候可以自己指定存储引擎
(2)指定存储引擎:在创建表的时候在语句后加 engine=xxx 就可以指定自己想使用的存储引擎了
(1)DML操作遵循ACID模型,支持事务
(2)行级锁,提高并发访问性能
(3)支持外键约束,保证数据的完整性和正确性
(1)不支持事务,不支持外键
(2)支持表锁,不支持行锁
(3)访问速度快
(1)如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入
和查询之外,还包含很多的更新、删除操作,那么选择 InnoDB 比较合适
(2)如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性
要求不是很高(比如日志和评论之类等),那么选择 MyISAM 比较合适
(1)顺序插入时,会形成一个链表,查询性能大大降低
(2)二叉树每个节点只能存储一个数据,大数据量情况下,层级较深,检索速度慢
(1)不支持范围查询
(2)无法利用索引完成排序操作
(3)查询效率高,通常只需要一次检索就可以了,效率通常要高于B+树索引
(4)在Mysql中,支持hash索引的是Memory引擎,而Inonodb中具有自适应hash功能,hash索引是存储
引擎根据B+树索引在指定条件下自动构建的
(1)相对于二叉树,层级更少,搜索效率高
(2)对于B树,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值,指针跟着减少,
要同样保存大量数据的话,就只能增加树的高度,导致性能降低
(3)相对于hash索引,B+树支持范围匹配及排序操作
(1)聚集索引:将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据,必须有且只有一个
(2)二级索引:将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键,可以存在多个
(1)首先查找二级索引中的Arm,拿到对应的主键
(2)再查找主键索引,查出所在行的数据
(1)如果存在主键,主键索引就是聚集索引
(2)如果不存在主键,将使用第一个唯一索引作为聚集索引
(3)如果表没有主键或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
(1)高度为2:
因为数据存储在叶子节点,所以非叶子节点只存储指针和主键,指针比主键多存储一个,
而一页默认大小为16KB则:n*8+(n+1)*6=16*1024 -> n约为1170
1171*16=18736
(2)高度为3:
1171*1171*16=21939856
(1)创建索引:
create [unique|fulltext] index index_name on table_name(index_col_name,...);
[unique|fulltext]表示可以选择创建哪种索引,不写的话就是创建普通索引
index_name:索引名 table_name:表名 index_col_name:要给哪些字段创建索引(一个或多个)
(2)查看索引:
show index from table_name;
(3)删除索引:
drop index index_name on table_name
(1)如果使用了联合索引,要遵守最左前缀法则
(2)最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳过某一列,索引将
部分失效(后面的字段索引失效)
(1)在索引列上进行运算操作
(2)字符串类型字段使用时,不加引号
(3)模糊查询时,如果仅仅是尾部模糊匹配,索引不会失效;如果是头部模糊匹配,索引失效
(4)用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么设计的索引不会被用到
(5)如果mysql评估使用索引比全表更慢,则不使用索引
(1)覆盖索引:查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到,不需要回表查询
(2)回表查询:在当前索引中没找到需要查询的字段,需要使用查找到的id再从聚集索引中查找一次。
先扫描辅助索引,再扫描聚集索引
(1)当字段类型为字符串时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的
磁盘IO,影响查询效率
(2)此时可以只将字符串的一部分前缀建立索引,这样可以大大节约索引空间,从而提高索引效率
(1)单列索引:一个索引只包含单个列
(2)联合索引:一个索引包含多个列
(3)如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引
(1)针对于数据量较大,且查询比较频繁的表建立索引
(2)针对于常作为查询条件 where order by(排序) group by(分组) 操作的字段建立索引
(3)尽量选择区分度高的列作为索引,尽量建立唯一索引,索引区分度越高,使用索引的效率越高
(4)如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引
(5)尽量建立联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表
提高查询效率
(6)要控制索引的数量,索引并不是多多益善的,索引越多,维护索引结构的代价也就越大,会影响增删改的效率
(7)如果索引列不能存储null值,请在创建表时使用 not null 约束它。当优化器知道每列是否包含null值
时,它可以更好的确定哪个索引最有效的用于查询
(1)想要插入多条SQL语句,建议批量插入
(2)手动事务提交
(3)主键顺序插入
(4)如果要一次性插入大批量数据,使用load指令进行插入
(1)在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表
(2)主键应该顺序插入,乱序插入的话可能会造成页分裂现象
(3)删除记录时,当页中删除的记录达到50%(默认),Innodb会寻找最靠近的页看看是否可以将两个页合并
以优化空间
(4)尽量降低主键的索引
(5)插入数据时尽量选择顺序插入,选择使用自增主键
(1)根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则
(2)尽量使用覆盖索引
(3)多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则
(4)using index:直接通过索引返回数据,性能高
(5)using filesort:需要将返回的结果在排序缓冲区排序
(1)在分组操作时,可以通过索引提高效率
(2)分组查询时,索引的使用也满足最左前缀法则
(1)可以通过覆盖索引加子查询的形式进行优化
(1)自己使用一个数据结构计数
(1)Innodb的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效
(2)在更新时要使用索引,否则会从行锁升级为表锁
(3)尽量根据主键/索引字段进行数据更新
(1)视图是一种虚拟存在的表,视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中
使用的表,并且是在使用视图时动态生成的
(2)视图只保存了查询的SQL逻辑,不保存查询结果,所以我们在创建视图的时候,主要的工作就落在创建
这条SQL查询语句上
(3)创建视图:create [or replace] view 视图名称[(列名列表)] as select语句
create or replace view stu_view1 as select id,name from student;
(4)查看创建视图语句:show create view 视图名称
查看视图数据:select * from 视图名称
(5)修改视图:使用创建视图的语句,or replace 必须加上
alter view 视图名称 as select语句
(6)删除视图:drop view [if exists] 视图名称
(1)使用视图插入的数据其实是插入到创建视图的那个基表
(1)当在创建视图时,当在SQL语句后加 with check option,mysql会通过视图检查正在更改的每个行,
例如 插入 更新 删除,以使其符合视图的定义。mysql允许基于另一个视图创建视图,它还会检查依赖
视图中的规则以保持一致性。为了确定检查范围,mydql提供了两个选项 cascaded 和 local,默认为
cascaded
(2)cascaded:进行视图检查时,还会检查当前视图依赖的视图的条件
(3)local:进行试图检查时,如果依赖的视图没有加检查选项,就不会去进行条件检查
(1)要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系
不可更新:
(2)创建视图时使用了聚合函数或窗口函数(sum min max count)
(3)创建视图时使用了distinct
(4)创建视图时使用了 group by
(5)创建视图时使用了 having
(6)创建视图时使用了 union 或者 union all
(1)简单:视图不仅可以简化用户对数据的理解,也可以简化它们的操作。那些被经常使用的查询可以被
定义为视图,从而使得用户不必为以后的操作每次指定全部的条件
(2)安全:通过视图用户只能查询和修改它们所能见到的数据
(3)数据独立:视图可以帮助用户屏蔽真实表结构变化带来的影响
(1)存储过程是事先经过编译并存储在数据库的一段SQL语句,调用存储过程可以简化应用开发人员的很多工作,
减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的
(2)存储过程思想上很简单,就是数据库SQL语言层面的代码封装和重用
(1)封装 复用
(2)可以接收参数,也可以返回数据
(3)减少网络交互,效率提升
(1)对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新
操作的事务提交语句都将被阻塞
(2)典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性
问题:
(3)如果从主库上备份,那么在备份期间都不能执行更新,业务基本上停摆
(4)如果从从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志,会导致主从延迟
(1)每次操作锁住整张表,锁定粒度大,发生锁冲突的概率最高,并发度最低
(1)表共享读锁(读锁):不会阻塞当前客户端和其它客户端的读操作,会阻塞其它客户端的写操作,会对当前
客户端的写操作报错
(2)表独占写锁(写锁):只允许当前客户端进行读操作和写操作,其它客户端的读操作和写操作都阻塞
(1)元数据锁加锁过程是系统自动控制的,无需显式使用,在访问一张表的时候会自动加上。
(2)元数据锁主要作用是维护表元数据的数据一致性,在表上有活动事务时,不可以对元数据进行写入操作
(3)当对一张表进行增删改查时,加MDL读锁(共享);当对表结构进行变更操作时,加MDL写锁(排他)
(1)为了避免DML在执行时,加的行锁与表锁冲突,在Innodb中引入了意向锁,使得表锁不用检查每行数据
是否加锁,使用意向锁来减少表锁的检查。如果要加的表锁与当前表的意向锁兼容,就直接加锁,不然的话
就阻塞
(2)意向共享锁(IS):与表锁共享锁兼容,与表锁排他锁互斥
(3)意向排他锁(IX):与表锁共享锁及排他锁都互斥,意向锁之间不会互斥
(1)每次操作锁住对应的行数据,锁的粒度最小,发生锁冲突的概率最低,并发度最高
(2)应用在Innodb存储引擎中,Innodb的数据是基于索引组织的,行锁是通过对索引上的索引项加锁
来实现的,而不是对记录加的锁
(1)锁定单个行记录的锁,防止其他事务对此进行update和delete,在RC RR隔离级别下都支持
(2)共享锁(S):允许一个事务去读一行,阻止其它事务获得这一行的排他锁
(3)排他锁(X):允许获取排他锁的事务更新数据,阻止其它事务获得这一行的共享锁和排他锁
(1)锁定索引记录间隙(不包含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert
,产生幻读。在RR隔离级别下支持
(2)间隙锁唯一目的是防止其他事务插入间隙,以防止幻读间隙锁可以共存,一个事务采用的间隙锁
不会阻止另一个事务在同一间隙上采用间隙锁
(3)索引上的等值查询(唯一索引):给不存在的记录加锁时,优化为间隙锁
(4)索引上的等值查询(普通索引):向右遍历时最后一个值不满足查询需求时,退化为间隙锁
(1)行锁和间隙锁的组合,同时锁住数据和锁住数据前面的间隙,在RR隔离级别下支持
(2)索引上的范围查询(唯一索引):会访问到不满足条件的第一个值为止,会加上临键锁
(1)重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性的
(2)该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),
前者是在内存中,后者在磁盘中。
(3)当事务提交之后会把所有修改信息都保存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据
恢复使用
(1)回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚和MVCC
(2)undo log 和 redo log 记录物理日志不一样,它记录的是逻辑日志
(3)undo log 销毁:undo log 在事务执行时产生,事务提交时并不会立即删除,因为这些日志可能还用于
MVCC
(4)undo log 存储:undo log 采用段的方式进行管理和记录
(1)当前读:读取的是记录的最新版本,读取时还要保证其它并发事务不能修改当前记录,会对读取的记录
进行加锁
(2)快照读:简单的select语句就是快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,
是非阻塞读
读已提交:每次select,都生成一个快照读
可重复读:开启事务后第一个select语句才是快照读的地方
串行化:快照读会退化为当前读
(3)MVCC:多版本并发控制,指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MYSQL实现
MVCC提供了一个非阻塞读功能。MVCC的具体实现还需要依赖于数据库记录中的三个隐藏字段、
undo log 日志、readView
(1)DB_TRX_ID:最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID
(2)DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合 undo log
(3)DB_ROW_ID:隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段
(1)回滚日志,在 insert update delete 的时候产生的便于数据回滚的日志
(2)当insert的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可被立即删除
(3)而 update delete 的时候,产生的 undo log 日志不仅在回滚时需要,在快照读时也需要,
不会立即被删除
(4)undo log 版本链:不同事务或相同事务对同一条记录进行修改,会导致该记录的 undo log 生成
一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧纪录
undo log 版本链
(1)readview是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的事务)id
包含四个核心字段:
(1)m_ids:当前活跃的事务ID集合
(2)min_trx_id:最小活跃事务ID
(3)max_trx_id:预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
(4)creator_trx_id:readview创建者的事务ID
不同的隔离级别,生成readview的时机不同
(1)读已提交:在事务中每一次执行快照读时生成readview
(2)可重复读:仅在事务中第一次执行快照读时生成readview,后续复用该readview