八股文篇-MySql

SQL语句的执行过程:

客户端的数据库驱动与数据库连接池:

(1)客户端与数据库进行通信前,通过数据库驱动与MySQL建立连接,建立完成之后,就发送SQL语句

(2)为了减少频繁创建和销毁连接造成系统性能的下降,通过数据库连接池维护一定数量的连接线程,当需要进行连接时,就直接从连接池中获取,使用完毕之后,再归还给连接池。常见的数据库连接池有 Druid、C3P0、DBCP

MySQL架构的Server层的执行过程:

(1)连接器:主要负责跟客户端建立连接、获取权限、维持和管理连接

(2)查询缓存:优先在缓存中进行查询,如果查到了则直接返回,如果缓存中查询不到,再去数据库中查询。

MySQL缓存是默认关闭的,也就是说不推荐使用缓存,并且在MySQL8.0 版本已经将查询缓存的整块功能删掉了。这主要是它的使用场景限制造成的:

先说下缓存中数据存储格式:key(sql语句)- value(数据值),所以如果SQL语句(key)只要存在一点不同之处就会直接进行数据库查询了;

由于表中的数据不是一成不变的,大多数是经常变化的,而当数据库中的数据变化了,那么相应的与此表相关的缓存数据就需要移除掉;

(3)解析器/分析器:分析器的工作主要是对要执行的SQL语句进行词法解析、语法解析,最终得到抽象语法树,然后再使用预处理器对抽象语法树进行语义校验,判断抽象语法树中的表是否存在,如果存在的话,在接着判断select投影列字段是否在表中存在等。

(4)优化器:主要将SQL经过词法解析、语法解析后得到的语法树,通过数据字典和统计信息的内容,再经过一系列运算 ,最终得出一个执行计划,包括选择使用哪个索引

在分析是否走索引查询时,是通过进行动态数据采样统计分析出来;只要是统计分析出来的,那就可能会存在分析错误的情况,所以在SQL执行不走索引时,也要考虑到这方面的因素

(5)执行器:根据一系列的执行计划去调用存储引擎提供的API接口去调用操作数据,完成SQL的执行


mysql的存储引擎

概念:

存储引擎类型:

InnoDB存储引擎

InnoDB引擎调优:

MyISAM存储引擎:

特点

MyISAM引擎调优精要

mysql锁机制

mysql锁可以划分为:

  1. 按照锁的粒度划分:行锁、表锁、页锁;
  2. 按照锁的使用方式划分:共享锁、排它锁(悲观锁的一种实现);
  3. 还有两种思想上的锁:悲观锁、乐观锁;
  4. InnoDB中有几种行级锁类型:Record Lock、Gap Lock、Next-key Lock。

MySQL的锁机制最显著的特点是不同的存储引擎支持不同的锁机制。比如,

MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);

BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;

InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

行锁

特点:偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。有可能会出现死锁的情况

脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

表锁

虽然使用行级索具有粒度小、并发度高等特点,但是表级锁有时候也是非常必要的:

特点:偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低

我们在编辑表,或者执行修改表的事情了语句的时候,一般都会给表加上表锁,可以避免一些不同步的事情出现,表锁分为两种,一种是读锁,一种是写锁。

加锁:

lock table 表名 read(write);

释放锁:

unlock tables;

查看加的锁:

show open tables;

加读锁(共享锁):

我们给表加上读锁会有什么效果呢?

1、我们加读锁的这个进程可以读加读锁的表,但是不能读其他的表。

2、加读锁的这个进程不能update加读锁的表。

3、其他进程可以读加读锁的表(因为是共享锁),也可以读其他表

4、其他进程update加读锁的表会一直处于等待锁的状态,直到锁被释放后才会update成功。

加写锁(独占锁):

1、加锁进程可以对加锁的表做任何操作(CURD)。

2、其他进程则不能查询加锁的表,需等待锁释放

总结:

读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞。(特别注意进程)

脏读、不可重复读和幻读

参考文档:https://zhuanlan.zhihu.com/p/514835631

简介

经常有面试官提出这么一个问题:什么是脏读、不可重复读和幻读?

关于这个问题,我们还得从数据库的管理系统说起,当数据库管理系统在写入或者更新数据的过程中,为了保证数据是正确可靠的,需要满足四个特性:原子性一致性隔离性和持久性,简称 ACID !

在事务的四个特性里面,其中隔离性总共分为四种级别:由低到高依次为 Read uncommitted 、Read committed 、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读等这几类问题。


场景分析

2.1、脏读

所谓的脏读,指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会保存到数据库,也可能会回滚,不保存到数据库。当这个数据发生了回滚,就意味着这个数据不存在,这就是脏读!



脏读最大的问题就是可能会读到不存在的数据。比如在上图中,事务 B 的更新数据被事务 A 读取,但是事务 B 回滚了,更新数据全部还原。也就是说事务 A 刚刚读到的数据并没有存在于数据库中。

从结果上看,事务 A 读出了一条不存在的数据,这个问题比较很严重!

当数据库的事务隔离级别为读未提交,就会发生脏读现象!

2.2、不可重复读

不可重复读,指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。



比如上图,事务 A 两次读取同一数据,第一次读取结果为 1,当事务 B 修改了数据并提交,此时的事务 A 第二次读取结果为 2,两次读取结果不一致!

当数据库的事务隔离级别为读未提交读提交时,就会发生不可重复读现象!

2.3、幻读

幻读和不可重复读,有点类似,但是表达的侧重点不一样。

例如事务 A 对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。此时,突然事务 B 插入了一条数据并提交了,当事务 A 提交了修改数据操作之后,再次读取全部数据,结果发现还有一条数据未更新,给人感觉好像产生了幻觉一样。这就是幻读!



当有别的事务,在插入或者删除同一条数据的时候,就容易产生幻读的现象!

当数据库的事务隔离级别为读未提交读提交可重复读时,就会发生幻读现象!

如何解决

为了解决上述问题,数据库通过锁机制来解决并发访问的问题。

以 Mysql 为例,根据锁定对象不同,分为:行级锁和表级锁;根据并发事务锁定的关系上看,分为:共享锁定和独占锁定

共享锁定会防止独占锁定,但允许其他的共享锁定;而独占锁定既防止共享锁定也能防止其他独占锁定;为了更改数据,数据库在进行更改的行上施加了行级独占锁定,insert、update、delete和selsct for update语句都会隐式采用必要的行锁定,当冲突加剧,会上升到表级锁定,此时会影响到其他表的访问操作。

直接使用锁机制管理是很复杂的,基于锁机制,数据库给用户提供了不同的事务隔离级别,只要设置了事务隔离级别,数据库就会分析事务中的 sql 语句然后自动选择合适的锁,可以依次有效的解决脏读、不可重复读和幻读问题!

整体的来说,事务的隔离级别和数据库并发性是成反比的,隔离级别越高,并发性越低。


MySQL之MVCC原理

参考文档:

https://www.cnblogs.com/xuwc/p/13873611.html

https://zhuanlan.zhihu.com/p/451830526


MVCC (Multi-Version Concurrency Control) (注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)是一种基于多版本的并发控制协议,只有在InnoDB引擎下存在。MVCC是为了实现事务的隔离性,通过版本号,避免同一数据在不同事务间的竞争,你可以把它当成基于多版本号的一种乐观锁。当然,这种乐观锁只在事务级别提交读和可重复读有效。MVCC最大的好处,相信也是耳熟能详:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能。


OLTP

联机事务处理OLTP(on-line transaction processing) 主要是执行基本日常的事务处理,比如数据库记录的增删查改。比如在银行的一笔交易记录,就是一个典型的事务。

实时性要求高。我记得之前上大学的时候,银行异地汇款,要隔天才能到账,而现在是分分钟到账的节奏,说明现在银行的实时处理能力大大增强。

数据量不是很大,生产库上的数据量一般不会太大,而且会及时做相应的数据处理与转移。

交易一般是确定的,比如银行存取款的金额肯定是确定的,所以OLTP是对确定性的数据进行存取

高并发,并且要求满足ACID原则。比如两人同时操作一个银行卡账户,比如大型的购物网站秒杀活动时上万的QPS请求。

OLAP

联机分析处理OLAP(On-Line Analytical Processing) 是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。典型的应用就是复杂的动态的报表系统。

实时性要求不是很高,比如最常见的应用就是天级更新数据,然后出对应的数据报表。

数据量大,因为OLAP支持的是动态查询,所以用户也许要通过将很多数据的统计后才能得到想要知道的信息,例如时间序列分析等等,所以处理的数据量很大;

OLAP系统的重点是通过数据提供决策支持,所以查询一般都是动态,自定义的。所以在OLAP中,维度的概念特别重要。一般会将用户所有关心的维度数据,存入对应数据平台。

什么是MVCC

多版本控制: 指的是一种提高并发的技术。最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。

在内部实现中,InnoDB通过undo log保存每条数据的多个版本,并且能够找回数据历史版本提供给用户读,每个事务读到的数据版本可能是不一样的。在同一个事务中,用户只能看到该事务创建快照之前已经提交的修改和该事务本身做的修改。

MVCC只在已提交读(Read Committed)和可重复读(Repeatable Read)两个隔离级别下工作,其他两个隔离级别和MVCC是不兼容的。因为未提交读,总数读取最新的数据行,而不是读取符合当前事务版本的数据行。而串行化(Serializable)则会对读的所有数据多加锁。

MVCC的实现原理主要是依赖每一行记录中两个隐藏字段,undo log,ReadView

什么是当前读和快照读?

说白了MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现


InnoDB MVCC 原理

InnoDB在每行数据都增加三个隐藏字段,一个唯一行号,一个记录创建的版本号,一个记录回滚的版本号。

在多版本并发控制中,为了保证数据操作在多线程过程中,保证事务隔离的机制,降低锁竞争的压力,保证较高的并发量。在每开启一个事务时,会生成一个事务的版本号,被操作的数据会生成一条新的数据行(临时),但是在提交前对其他事务是不可见的,对于数据的更新(包括增删改)操作成功,会将这个版本号更新到数据的行中,事务提交成功,将新的版本号更新到此数据行中,这样保证了每个事务操作的数据,都是互不影响的,也不存在锁的问题。


Mysql事务实现机制

事务时是访问和更新数据的程序执行单元,事务中可能含有一个或多个SQL语句,这些语句要么全部执行,要么都不执行。

ACID是衡量事务的四个标准:

只有同时满足ACID特性才是事务。


原子性:语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log。

持久性:保证事务提交后不会因为宕机等原因导致数据丢失;实现主要基于redo log。

隔离性:保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR(可重复读),RR的实现主要基于锁机制(包含next-key lock)、MVCC(包括数据的隐藏列、基于undo log的版本链、ReadView)。

一致性:事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障。



原子性实现

原子性指一个事务是一个不可分割的整体,内部所有的操作要么都做,要么都不做,如果事务中的一条SQL执行失败,那么已经执行的语句也必须回滚.所以说,实现原子性的核心就在于如何实现回滚

首先介绍一下MySQL的事务日志,MySQL的日志有很多种,比如二进制日志(binlog)、错误日志、查询日志、慢查询日志,此外InnoDB存储引擎还提供了两种事务日志,redo log(重做日志) 和 undo log(回滚日志), 其中redo log用于保证事务的持久性,而undo log则是事务原子性和隔离性实现的基础。

实现原子性的关键,是当事务回滚时能够撤销所有已经执行成功的SQL语句,InnoDB实现回滚,靠的是undo log,当事务对数据库进行修改时,InnoDB会生成对应的;如果事务执行失败或者调用了rollback,导致事务需要回滚,就利用undo log中的信息将数据回滚到修改之前的样子

undo log属于逻辑日志,它记录的是SQL执行相关的信息,当发生回滚时,InndDB会根据undo log的内容做与之前相反的工作,对于每个insert,回滚时会执行delete,对于每个update,回滚时会执行一个相反的update,将数据改回去。

以update操作为例,当事务执行update时,其生成的undo log中会包含被修改行的主键(一遍知道修改了哪些行),修改了哪些列、这些列在修改前后的值的信息,回滚时便可以使用这些信息将数据还原到update之前的状态。

持久性实现

持久性指事务一旦提交,它对数据库的改变就应该是永久的,接下来的其他操作不应该对其有任何影响,并且不能回滚。

redo log与undo log都属于InnoDB的事务日志,下面聊一下redo log存在的背景。

InnoDB作为MySQL的存储引擎,数据时放在磁盘的,但是如果每次读写数据都需要磁盘IO,效率会很低,为此,InnoDB提供了缓存(Buffer Pool),BP中包含了部分数据页的映射,作为访问数据库的缓冲;当从数据库读取数据时,会首先写入BP,BP中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)。

BP的使用大大提高了读写数据的效率,但是也带来了新的问题,如果MySQL宕机,而此时BP中修改的数据还没有刷新的磁盘,就会导致数据的丢失,事务的持久性无法保证。

redo log就被引入来解决这个问题(宕机导致BP中的数据没有刷新磁盘,造成数据丢失),当数据被修改时,除了修改BP中的数据,还会在redo log中记录这次操作,当事务提交时,会调用fsync接口对 redo log进行刷盘,如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复,redo log采用的是WAL(Write-ahead logging,预写式日志), 所有修改先写入日志,在更新到BP,保证了数据不会因为MySQL宕机而丢失,从而满足了持久性的要求。


  1. 刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。
  2. 刷脏是以数据页(Page)为单位的,MySQL默认页的大小是16KB,一个Page上一个小修改都要整页写入,而redo log中只包含真正需要写入的部分,无效IO大大的减少。


我们知道,在MySQL中还存在 binlog(二进制日志) 也可以记录写操作并用于数据的恢复,但二者是有着根本的不同的:

(1)作用不同:redo log是用于crash recovery的,保证MySQL宕机也不会影响持久性;binlog是用于point-in-time recovery的,保证服务器可以基于时间点恢复数据,此外binlog还用于主从复制,binlog简单描述binlog实现主从复制原理以及工作流程

(2)层次不同:redo log是InnoDB存储引擎实现的,而binlog是MySQL的服务器层(可以参考文章前面对MySQL逻辑架构的介绍)实现的,同时支持InnoDB和其他存储引擎。

(3)内容不同:redo log是物理日志,内容基于磁盘的Page;binlog的内容是二进制的,根据binlog_format参数的不同,可能基于sql语句、基于数据本身或者二者的混合。

(4)写入时机不同:binlog在事务提交时写入;redo log的写入时机相对多元:

前面曾提到:当事务提交时会调用fsync对redo log进行刷盘;这是默认情况下的策略,修改innodb_flush_log_at_trx_commit参数可以改变该策略,但事务的持久性将无法保证。

除了事务提交时,还有其他刷盘时机:如master thread每秒刷盘一次redo log等,这样的好处是不一定要等到commit时刷盘,commit速度大大加快。

隔离性实现

与原子性和持久性侧重与研究事务本身不同,隔离性研究的是不同事务之间的相互影响,隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰,严格的隔离性对应了事务的隔离级别中的Serializable(可串行化),但实际应用中处于性能考虑很少会使用次级别

隔离性追求的是并发情况下事务之间互不干扰,简单起见,我们主要考虑最简单的读操作和写操作(加锁读等特殊情况会特殊说明),那么隔离性的探讨,主要可以分为两个方面。

锁机制的基本原理可以概括为:事务在修改数据之前,需要先获得相应的锁;获得锁之后,事务便可以修改数据;该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。(共享锁和独占锁)

一致性实现

一致性是指事务执行的结果必须是使数据库从一个一致性状态变到另一个一致状态,即数据库的完整性没有被破坏,事务执行的前后都是合法的状态。数据库的完整性包括但不限于:实体完整性(如行的主键存在且唯一)、列完整性(如字段的类型、大小、长度要符合要求)、外键约束、用户自定义完整性

可以说,一致性是事务追求的最终目标:前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。此外,除了数据库层面的保障,一致性的实现也需要应用层面进行保障。


实现一致性的措施包括:

保证原子性、持久性和隔离性,如果这些特性无法保证,事务的一致性也无法保证。

数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等。

应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致。


参考文档:

https://blog.csdn.net/qq_46312987/article/details/123941617?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-123941617-blog-123115659.pc_relevant_recovery_v2&spm=1001.2101.3001.4242.1&utm_relevant_index=2

https://blog.csdn.net/qq_46312987/article/details/123956237?spm=1001.2014.3001.5501



Mysql binlog详解

简介:

MySQL的二进制日志binlog可以说是MySQL最重要的日志,它记录了所有的DDL和DML语句(除了数据查询语句select),以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二进制日志是事务安全型的。

DDL ----Data Definition Language 数据库定义语言

主要的命令有create、alter、drop等,ddl主要是用在定义或改变表(table)的结构,数据类型,表之间的连接和约束等初始工作上,他们大多在建表时候使用。

DML ----Data Manipulation Language 数据操纵语言

主要命令是slect,update,insert,delete,就像它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言

使用场景

mysql主从复制:

mysql replication在master端开启binlog,master把它的二进制日志传递给slaves来达到master-slave数据一致的目的。

数据恢复:

通过mysqlbinlog工具来恢复数据。

binlog日志包括两类文件:

1)、二进制日志索引文件(文件名后缀为.index)用于记录所有的二进制文件。

2)、二进制日志文件(文件名后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句select)语句事件。

数据同步

ES数据同步,监听mysql binlog 然后投递到MQ中,下游消费MQ,将数据写入的ES中。

多数系统会分为B端C端,B端查询比较复杂对数据实时性敏感较低,因此可以使用ES做查询,通过binlog的方式可以异步同步到ES中。

展开阅读全文

页面更新:2024-03-07

标签:持久性   缓存   语句   加锁   索引   事务   操作   数据库   引擎   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top