高性能mysql 读书笔记 MySQL架构

1.MySQL逻辑架构

在这里插入图片描述

  1. 第一层所说的客户端应该就是mysql workbench。负责连接处理,授权认证,安全等。
  2. 第二层架构是MySQL的核心,核心的服务功能都在这一层。包括查询解析,分析,优化,缓存以及所有的内置函数(例如,日期,时间,数学和加密函数),所有夸存储引擎的功能都在这一层实现:存储功能,触发器,视图等。
  3. 第三层包含了存储引擎,存储引擎负责MySQL中数据的存储和提取。和GNU/Linux下的各种文件系统一样,每个存储引擎都有它的优势和劣势。服务器通过API与存储引擎进行通信。这些接口屏蔽不同存储引擎之间的差异,是的这些差异堆上层的查询透明。

2.并发控制

2.1读写锁

并发控制方式多是采用锁机制。
通常是共享锁(读锁)排他锁(写锁)
读锁是共享的,多个客户在同一个时刻可以同时读取同一个资源,互不干扰。加了读锁后可以再加读锁,但不可加写锁。
写锁是排他的,也就是说在写的同时不允许其他的写锁来写和读锁来读。这样就能防止脏数据的进入。

2.2锁粒度

锁需要消耗资源,锁的对象过大也影响并发性,锁过多也会消耗过多资源,所以锁粒度的大小会影响性能。所以锁策略就格外重要。MySQL提供了多种锁策略,下面介绍最重要的两个锁策略。

2.2.1表锁

表锁是Mysql中开销最小的锁。它的策略是会锁定一张表,如果用户对表写入(插入,更新,删除),就会将表锁住,同时阻塞其他的用户对这张表的读和写。在某些场景下,写锁比读锁更高的优先级。写锁请求会插入到读锁队列的前面,反之,读锁不能插入到写锁前面。

2.2.2 行级锁

行级锁可以最大成都地支持并发处理(同时带来了最大的锁开销)。行锁只在存储引擎层实现。

3.MySQL事务

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎能够成功地堆数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。

3.1事务的ACID

原子性(atomicity):一个事务必须被视为不可分隔的最小工作单元,整个事务中的所有操作要么全部提交成功要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。

一致性(consisitency):数据库总是从一个一致性的状态转换到另一个一致性的状态。

隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的。

持久性(durabilty):一旦事务提交,则其所做的修改就会永久保存到数据库中。

3.2 隔离级别

3.2.1 不使用隔离级别可能存在的问题

脏读:一个事务读了另一个事务修改了但未提交的数据。
不可重复读:在一个事务中多次读取同一个数据,但读取的数据不同。可能是被修改了或被删除了。
幻读:在一个事务中多次读取同一个数据集合,但读取的数据集合不同。可能是插入了新的数据。

3.2.2 隔离级别

每种存储引擎实现的隔离级别不尽相同。
READ UNCOMMITTED(未提交读)
在次级别中,事务中的修改即使没有提交在其他事务中也是可见的。其他事务可以读取未提交的数据。

READ COMMITTED(提交读)
只能读取已提交的事务所做的修改。
能解决脏读。
大多数数据库系统的默认隔离级别都是READ COMMITTED,但MySQL不是。

REPEATABLE READ(可重复读)
该级别保证在同一个事务中多次读取同样记录的结果是一致的。
解决了脏读和不可重复读。
可重复读是MySQL的默认事务隔离级别。

SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离级别。它强制事务串行执行,也就是一个一个执行。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁竞争。
解决了脏读,不可重复读和幻读。但效率低。

3.3 死锁

死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。

比如,事务A占用了资源1,事务B占用了资源2。同时地,事务A请求资源2,但事务B锁定了资源2,事务B请求资源1,但事务A锁定了资源1。于是就产生了死锁。

3.3.1 产生死锁的必要条件(插入一下操作系统的知识)

1.互斥条件:并发进程(在数据库中就是事务)锁要求和占有的资源是不能同时被两个以上进程使用或操作的,进程对它所需要的资源进行排他性控制。
2.不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行剥夺,而只能有获得该资源的进程自己释放。
3.部分分配。进程每次申请它所需要的一部分资源,在等待新资源的同时,继续占用已分配到的资源。(意思就是资源不同时分配,是有先后顺序的,正因为有先后才能导致死锁。)
4.环路条件:存在一种进程循环链,链中每一个进程已获得的资源同时被下一个进程所请求。

只要使上述4个必要条件中的某一个不满足,死锁就可以消除。

3.4 事务日志

事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再吧该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘中。这有什么区别呢?事务日志采用的是追加的方式,使用写日志的操作是磁盘上一下快区域内的顺序I/O,而不想每次修改数据的随机I/O。随机I/O需要磁盘的磁头在多个地方移动,效率很低,使用事务日志能提高效率。事务日志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。我们通常称之为预写式日志。

3.4.1 redo和undo日志的区别(这也是我自己插入的)

undo是指数据库为了保持读一致性,存储历史数据在一个位置。undo日志用于存放数据修改被修改前的值,如果这个修改出现异常,可以使用undo日志来实现回滚操作,保证事务的一致性。
​ 当数据库对数据做修改的时候,需要把数据页从磁盘读到buffer pool中,然后在buffer pool中进行修改,那么这个时候buffer pool中的数据页就与磁盘上的数据页内容不一致,称buffer pool的数据页为dirty page 脏数据,如果这个时候发生非正常的DB服务重启,那么这些数据还没在内存,并没有同步到磁盘文件中(注意,同步到磁盘文件是个随机IO),也就是会发生数据丢失,如果这个时候,能够在有一个文件,当buffer pool 中的data page变更结束后,把相应修改记录记录到这个文件(注意,记录日志是顺序IO),那么当DB服务发生crash的情况,恢复DB的时候,也可以根据这个文件的记录内容,重新应用到磁盘文件,数据保持一致。

3.5 MySQL中的事务

MySQL提供了两种事务的存储引擎:InnoDB和NDB Cluster。另外还有一些第三方存储引擎也支持事务,比较知名的包括XtraDB和PBXT。

3.5.1 自动提交

MySQL默认采用自动提交(autocommit)模式。也就是说不是显式的开始一个事务,则每个查询都被当作一个事务执行提交操作。在当前连接中,可以通过设置autocommit变量来弃用或禁用自动提交模式:
在这里插入图片描述
1或者ON表示启用,0或者OFF表示禁用。当autocommit=0时,所有的查询都是在一个事务中,直到显式地执行COMMIT提交或者ROLLBACK回滚,该事务结束,同时又开始新事务。

**修改autocommit对非事务型的表,比如MyISAM或者内存表,不会有任何影响。**堆这类表来说,没有COMMIT或者ROLLBACK的概念(因为根本就没事务),也可以说是相当于一直处于autocommit启用的模式。

有一些命令在执行之前会强制执行COMMIT提交当前的活动事务。 比如在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如ALTER TABLE。

MySQL可以通过执行SET TRANSACTION ISOLATION LEVEL 命令来设置隔离级别。新的隔离级别会在下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以值改变当前会话的隔离级别:
在这里插入图片描述

3.5.2 在事务中混合使用存储引擎

MySQL服务器层(架构的第二层)不管理事务,事务是有存储引擎(第三层)实现的。所以在同一个事务中,使用多种存储引擎是不可靠的:

  • 如果在事务中混合使用了事务型和非事务型的表(例如InnoDB和MyISAM表),在正常提交的情况下不会有什么问题
  • 但如果该事务需要回滚,非事务型的表上的变更就无法撤销,这会导致数据库处于不一致的状态,这种情况就很难修复,事务的最终结果将无法确定。所以,为每张表选择合适的存储引擎非常重要。
  • 在非事务型的表上指向事务相关操作的时候,MySQL通常不会发出提醒,也不会报错。有时候只有回滚的时候才会发出一个警告:“某些非事务型的表上的变更不能被回滚”。但大多数情况下,对非事务型表的操作都不会有提示。

3.5.3 隐式和显式锁定

InnoDB采用的是两阶段锁协议。在事务执行过程时都是可以执行锁定的,锁只有在执行COMMIT或者ROLLBACK的时候才会释放,并且所有的锁是在同一时刻被释放。前面所描述的锁定都是隐式锁定,InnoDB会根据隔离级别在需要的时候自动枷锁。

InnoDB支持通过特定的语句进行显式加锁,不过这些语句不属于SQL规范:
在这里插入图片描述

4.多版本并发控制(MVCC)

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,他们一般都同时实现了多版本并发控制(MVCC)。

可以认为MVCC是航机所的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。

MVCC的实现:通过保存数据在某个时间的快照(可以理解为存储了时间戳和当时的数据)实现。
因为有了时间戳,事务就可以用事务开始的时间去读取快照,不同的开始时间可能读取不同的数据。(这也就解决了幻读)。

乐观锁和悲观锁

不同存储引擎的MVCC实现是不同的,有乐观锁和悲观锁。

乐观锁(Optimistic Lock)
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。

悲观锁(Pessimistic Lock)
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。

InnoDB的MVCC实现

InnoDB的MVCC是通过在每行记录后保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号(越晚产生的版本号,数值越大,所以你就可以理解为时间值)。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来查询到的每行记录的版本号比较。

使用这两个版本号使得大多数读操作都可以不用加锁。

MVCC只在REPEATABLE READ 和READ COMMITTED两个隔离级别下工作。READ UNCOMMITTED总是读取最新的数据行。SERIALIZABLE则会堆所有读取的行都加锁。

REPEATABLE READ 隔离模式下,MVCC具体操作:

(1)select
InnoDB会根据一下两个条件检查每行记录

  • InnoDB只查找版本遭遇当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或修改过的。
  • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。

只有符合上述两个条件的记录,才能返回作为查询结果。

(2)insert
InnoDB为新插入的每一行保存当前系统版本号作为行版本号。

(3)delete
InnoDB为删除的每一行保存当前系统版本号作为行删除标识。

(4)update
InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号为原来的行作为行删除标识。

5.MySQL的存储引擎

这个小结概要描述MySQL的存储引擎,不会设计太多细节。之后会再写一篇文章总结。

5.1 InnoDB存储引擎

InnoDB是MySQL的默认事务型引擎使用最广泛的存储引擎,一般优先使用InnoDB存储引擎,它被设计用来处理大量的短期事务,短期事务大部分情况是正常提交的,很少会回滚。

1.数据存储形式
InnoDB的数据存储在表空间中,表空间是由InnoDB管理的一个黑盒子,由一系列的数据文件组成。使用InnoDB时,会将数据表分为.frm和idb两个文件进行存储。.frm存储表结构,.ibd存储表的数据和索引。

2.锁的粒度
InnoDB采用MVCC来支持高并发,并且实现了四个标准的隔离级别。其默认级别是REPEATABLE READ,并通过间隙锁策略防止幻读的出现。间隙锁是的InnoDB不仅仅锁定查询设计的行,还会堆索引中的间隙进行锁定,防止幻影行的插入。

3.事务
InnoDB是典型的事务型存储引擎。

4.数据的存储特点
InnoDB表是基于聚簇索引建立的。聚簇索引对主键查询有很高的性能。不过它的二级索引中必须包含主键列,索引如果主键列很大的话,其他的所有索引都会很大。

5.2 MyISAM存储引擎

1.数据存储形式
MyISAM采用的是索引与数据分离的形式,将数据保存在三个文件中.frm.MYD,.MYIs。.frm存储表结构,.MYD存储表的数据,.MYI存储表索引。

2.锁的粒度
MyISAM不支持行锁,所以读取时对表加上共享锁,在写入是对表加上排他锁。由于是对整张表加锁,相比InnoDB,在并发写入时效率很低。

3.事务
MyISAM不支持事务。

4.数据的存储特点
MyISAM是基于非聚簇索引进行存储的。

5.其他
MyISAM提供了大量的特性,包括全文索引,压缩,空间函数,延迟更新索引键等。

进行压缩后的表是不能进行修改的,但是压缩表可以极大减少磁盘占用空间,因此也可以减少磁盘IO,从而提供查询性能。

全文索引,是一种基于分词创建的索引,可以支持复杂的查询。

延迟更新索引键,不会将更新的索引数据立即写入到磁盘,而是会写到内存中的缓冲区中,只有在清除缓冲区时候才会将对应的索引写入磁盘,这种方式大大提升了写入性能。

5.3 InnoDB与MyISAM的对比与选择

两种存储引擎各有各的有点,MyISAM专注性能,InnoDB专注事务。两者最大的区别就是InnoDB支持事务,和行锁。
在这里插入图片描述
如何在两种存储引擎中进行选择?

① 是否有事务操作?有,InnoDB。

②是否存储并发修改?有,InnoDB。

③是否追求快速查询,且数据修改较少?是,MyISAM。

④是否使用全文索引?如果不引用第三方框架,可以选择MyISAM,但是可以选用第三方框架和InnDB效率会更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值