逻辑架构概述

概述

  • 逻辑架构
    逻辑架构概述_第1张图片

    • 连接/线程处理:计算机网络部分,非MySQL独有
      • 每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行,服务器会负责缓存线程(不需要为每一个新建的连接创建或销毁进程)
      • MySQL5.5及以上提供了一个API支持线程池插件(预加载线程,之后反复使用)(1条消息) C++11并发学习之六:线程池的实现_草上爬的博客-CSDN博客_c++ 线程池
    • 中间层:核心服务功能,所有跨存储引擎的功能都在这一层,如存储过程,触发器,视图等
      • 优化与执行:创建解析树并进行优化,用户可通过关键字影响决策。优化器会请求存储引擎提供容量或某个具体操作的开销信息和表数据的统计信息,用于优化决策。
      • 服务器层和存储引擎层的并发控制
        • 共享锁和排他锁(读锁和写锁)
        • 锁粒度越小,并发程度越高:行级锁和表锁(锁定整张表,ALTER TABLE默认使用)
    • 存储引擎:数据的存储和提取。服务器通过API和它通信,接口屏蔽了不同存储引擎之间的差异。
  • 事务:一组原子性的SQL查询/一个独立的工作单元(要么全部执行,要么全部失败)ACID

    • START TRANSACTION / COMMIT / ROLLBACK
    • 原子性atomicity:一个事务被视为一个不可分割的最小工作单元
    • 一致性consistency:数据库总是从一个一致性状态转换到另一个一致性状态(数据正确)
    • 隔离性isolation:通常来说,最终提交前对其他事务不可见(隔离级别)
    • 持久性durability:提交后修改会永久保留
  • 隔离级别:较低级别的隔离通常可以执行更高的并发(SET SESSION TRANSACTION ISOLATION LEVEL……)

    • READ UNCOMMITTED(未提交读):事务中的修改即使没有提交对其他事务也都可见。脏读。

    • READ COMMITTED(提交读/不可重复读):大多数数据库系统的默认隔离级别。事务从开始到提交之前所作的任何修改对其他事务都不可见。两次执行同样的查询可能得到不同结果。

    • REPEATABLE READ(可重复读):MySQL级别,保证在同一事务中多次读取同样记录结果一致。幻读。

    • SERIALIZABLE(可串行化):强制事务串行处理
      逻辑架构概述_第2张图片
      写-读问题:

    • 脏读:事务可以读取到未提交的数据

      时间点 事务A 事务B
      1 开启事务
      2 开启事务
      3 查询数据为100条
      4 insert一条数据
      5 再查询,结果为101条
    • 不可重复读:两次执行同样查询结果不同(执行期间有新的commit)

      时间点 事务A 事务B
      1 开启事务
      2 开启事务
      3 查询数据为100条
      4 insert一条数据
      5 查询数据为100条
      6 提交事务
      7 查询数据为101条
    • 幻读:当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。本质是因为一个事务的**写入(插入)**改变了另一个事务的查询结果

      时间点 事务A 事务B
      1 开启事务
      2 开启事务
      3 查询数据“张三”,不存在
      4 插入数据“张三”
      5 提交事务
      6 查询数据“张三”,不存在
      7 插入数据“张三”,不成功

      事务A查询“张三”,查询不到插入又不成功,“张三”这条数据就像幻觉一样出现。这就是“幻读”。

    写-写问题:

    • 脏写:如果两个事务同时更新相同的对象,后写的操作会覆盖比较早的写入。但是如果先前的写入是尚未提交事务的一部分,并且被后写的事务所覆盖,就是脏写。保证不会出现该问题的隔离级别-提交读
    • 更新丢失:脏写是写事务并发场景下的一个特例,强调未提交事务的修改被覆盖。而更新丢失一般是由Read And Modify(读后改)操作导致的,比如有两个事务先获取了值A=42(读锁),然后再分别获取写锁执行加一的操作,那么显然最后两个事务更新的结果都为43,这就造成了更新丢失的问题
    • 写倾斜:写倾斜不同于脏写和更新丢失,一般是由Check then Act(检查后操作) 操作导致的,比如存在一个应用层条件:医院晚上必须有一个人值班,而当晚有两个员工同时按下了请假键,应用程序首先会查询数据库当前在岗人数是否 >1,因为同时按下,那么数据库的返回都是2,因而接下来便会将在岗人数依次获取写锁后-1,最终导致无一人在岗。保证不会出现该问题的事务隔离级别-串行化
  • MVCC(多版本并发控制)—— 通过保存数据在某个时间点的快照来实现

    • 我们可以以写事务的提交为时间点,为写事务所涉及到的行在数据库中保留两个共存的版本-新旧版本,使得在该事务提交前其他事务进行的相关行查询返回旧版,该事务提交后进行的查询返回新版。从而保证了在某个时间点开启的事务可以获取到一致的数据库状态。

    • 在每行记录后面保存两个隐藏列(行创建时间和删除时间),存储的是系统版本号,每开始一个新的事务系统版本号都会自动递增。根据这两列来完成操作。
      逻辑架构概述_第3张图片

    • Innodb为每个事务提供了一个全局递增的唯一标识trx_id,通过该标识判断多个事务请求数据库时间先后,并额外存储在每个聚簇索引的数据行中。

    • 为了保证事务的原子性,Innodb提供了undo日志Innodb将每个数据行对应的undo日志通过额外存储在每个数据行中的roll_pointer串联起来形成版本链,从而实现一个数据行在数据库中存储多个版本:
      逻辑架构概述_第4张图片

    • 在事务开始前,数据库中应该存在一个已经确定的数据行版本(即最近提交的一个事务对应的版本),可能还会存在一个或多个未提交的事务版本,Innodb通过ReadView和相应的行可见算法实现了在多个版本并存的情况下,通过trx_id确认当前事务所需要访问的数据行的版本

    • 对于每个事务,数据库都会为其生成一个ReadView对象,对象中存储数据库事务当前状态的快照

      • max_trx_id:当前数据库活跃事务列表中trx_id的最大值
      • min_trx_id:当前数据库活跃事务列表中trx_id的最小值
      • m_ids:当前数据库活跃事务的trx_id列表(正在执行的事务列表)
      • creator_trx_id:创建当前ReadView的事务id…
    • 对于读写事务而言,依据ReadView中的trx_id在与版本链中数据行的trx_id比较时会出现几种情况:

      • 当前数据行的trx_id在[min_trx_id, max_trx_id]之间
        • 当前事务的trx_id=当前数据行的trx_id,说明是当前事务本身的修改,自然对当前事务可见
        • 当前数据行的trx_id不在m_ids列表中,说明该数据行版本对应的事务已经被提交,则该数据行版本对于当前事务可见
        • m_ids列表中,说明修改该数据行的事务仍未提交,则对当前事务不可见。
      • 当前数据行trx_id>max_trx_id,说明该数据行版本是在生成当前ReadView之后建立的事务修改的,则该数据行版本对于当前事务不可见。
      • 当前数据行trx_id<min_trx_id,说明该数据行版本对应的事务已经被提交,则该数据行版本对于当前事务可见。
  • MVCC下的幻读问题:只能解决部分只读的幻读!

    • 当前读:读取的数据库记录都是当前最新的版本,会对当前读取的数据进行加锁,防止其他事务修改数据。是悲观锁的一种操作。而快照读作为MVCC的实现方式,是一种乐观锁,不会加锁。

    • 乐观锁无法解决写-写冲突。快照隔离级别可以避免只读查询时的幻读,对于存在update、delete、insert操作的事务,快照隔离级别并不能保证不出现幻读问题。(会导致其trx_id更新成当前的id)

      MySQL 如何解决幻读(MVCC 原理分析) - 掘金 (juejin.cn)

    • 通过MVCC与不同粒度的锁实现可串行化隔离级别

  • 死锁解决策略:InnoDB等复杂系统能够检测到死锁的循环依赖并立即返回一个错误/InnoDB处理方式是将持有最少行级排他锁的事务回滚。

  • 事务日志
    逻辑架构概述_第5张图片

  • MySQL默认采用自动提交AUTOCOMMIT模式:如果不是显示开始一个事务,则每一个查询都被当作一个事务执行提交操作。

    • 设置语句:SET AUTOCOMMIT = 1 (1/ON:启动;0/OFF:禁用)
    • 部分命令(如DDL)执行前会强制执行COMMIT提交。
  • 存储引擎:创建表时会在数据库子目录下创建一个和表同名的**.frm文件**保存表的定义(SHOW TABLE STATUS命令显示相关信息)

    • InnoDB存储引擎:MySQL默认事务型引擎,处理大量的短期事务
      • 数据存储在表空间中,表空间是由一系列数据文件组成
      • MVCC来支持高并发,REPEATABLE+间隙锁策略防止幻读,实现四个标准的隔离界别
      • 基于聚簇索引建立。内部采用可预测性预读,自适应哈希索引,插入缓冲区……
    • MyISAM存储引擎:最早的存储引擎之一。提供全文索引,压缩,空间函数等,但不支持事务和行级锁,且崩溃后无法安全恢复。设计简单,数据以紧密格式存储,适合只读数据,或表比较小,可以忍受修复操作的仍可以使用。
      • 只将数据写到内存,然后等待操作系统定期将数据刷出到磁盘上,故崩溃后无法安全回复。
      • 表存储在两个文件中:数据文件(.MYD)和索引文件(.MYI)。可包含动态或静态行。
      • 加锁与并发:表锁。读取加共享锁,写入加排他锁。
      • 修复:手工或自动,速度慢。CHECK TABLE mytable检查,REPAIR TABLE mytable修复
      • 索引特性:全文索引或基于前500个字符创建索引
      • 延迟更新索引键DELAY_KEY_WRITE:修改执行完成会先写入键缓冲区
      • MyISAM压缩表:不能修改(除非解压,修改再加压),减少磁盘空间占用和磁盘I/O,提升查询性能,索引只读。改进后记录单独压缩。
    • Archive引擎:只支持INSERT和SELETE(全表扫描)。行压缩,磁盘I/O比MyISAM少。适合日志和数据采集类型应用。支持行级锁和专用缓冲区。不是事务型引擎,而是针对高速插入和压缩做了优化的简单引擎
    • Blackhole引擎:丢弃所有插入数据,没有实现任何存储机制。
    • CSV引擎:将普通csv文件作为表处理,不支持索引。作为数据交换机制很有用

    (还有很多,省略)

  • 转换 表的引擎

    • ALTER TABLE:最简单的方法,耗时。按行将数据从原表复制到一张新的表中,复制期间可能会消耗系统所有的I/O能力,同时给原表加读锁。会失去原引擎相关的所有特性。

      mysql> ALTER TABLE mytable ENGINE = InnoDB;
      
    • 导出与导入:mysqldump工具将数据导出到文件,然后修改文件中CREATE TABLE语句的存储引擎选项并修改表明。(默认会再CREATE前加DROP TABLE)

    • 创建与查询CREATE和SELECT:综合了前两种,先创建一个新的存储引擎的表,然后利用INSERT……SELECT语句导数据

你可能感兴趣的:(MySQL,数据库,mysql,sql)