1.逻辑架构
1.概述
1.最上层的服务不是MySQL独有的,大多数基于网络的客户端/服务器的工具或者服务都会有类似的架构。比如连接处理、授权认证、安全等。
2.第二层包含大多数的MySQL核心服务功能。包括查询解析、分析、优化、缓存以及所有的内置函数,所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。
3.第三层包含了存储引擎,存储引擎负责MySQL中数据的存储和提取。服务器通过API和存储引擎进行通信,存储引擎不解析SQL,不同存储引擎之间不会通信,他们只是简单的响应上级服务器的请求。
2.连接管理和安全性
每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行,该线程只能轮流在某个CPU核心或者CPU中运行。
当客户端连接到MySQL服务器时,服务器需要对其进行验证。验证是基于原始主机信息、用户名、密码,客户端连接成功后,服务器继续验证客户端的查询权限。
3.优化与执行
MySQL会解析查询,并创建内部数据结构,然后对其进行各种优化,包括重写查询、决定表的读取顺序以及选择合适的索引等。用户可以通过特殊的关键字提示(hint)优化器,影响它的决策过程。也可以请求
优化器解释(explain)优化过程的各个因素。
优化器并不关心表使用的什么存储引擎,但存储引擎对优化是有影响的。优化器会请求存储引擎提供容量或某个具体操作的开销信息,以及表数据的统计信息等。
对于SELECT语句,在解析查询前,服务器会先检查缓存(Query Cache),如果缓存中有就不必再执行查询解析、优化和执行的整个过程,而直接返回缓存的结果。
2.并发控制
1.概述
无论何时,只要有多个查询在同一时刻修改数据,都会产生并发控制的问题。
2.读写锁
并发控制:在处理并发读或者写时可以通过实现一个由两种类型的锁组成的锁系统来解决问题。这两种类型的锁通常被称为共享锁和排它锁,也叫读锁和写锁。
读锁是共享的,或者说是相互不阻塞的,多个客户在同一时刻可以同时读取同一个资源,而互不干扰。写锁是排它的,也就是说一个写锁会阻塞其它的写锁和读锁。
3.锁的粒度
一种提高共享资源并发性的方式是让锁定对象更加有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。更理想的是,只对修改的数据偏进行精确的锁定。
任何时候,在给定的资源上,锁定的数量越少,则系统并发程度越高,只要相互之间不发生冲突即可。但是加锁也需要消耗资源,锁的各种操作都会增加系统的开销。
因此锁的策略,就是在锁的开销和数据的安全性之间寻求平衡。
表锁:最基本、开销最小的锁策略。它会锁定整张表,一个用户在对表进行写操作前,需要先获得写锁,这会阻塞其它用户对该表的所有读写操作,只有没有写锁时,其它
用户才能获得读锁,读锁之间不会相互阻塞。注意,尽管存储引擎可以管理自己的锁,但服务器有时会使用自己的锁,而忽略存储引擎的锁,比如ALTER TABLE用的就只是表锁。
行锁:行锁可以最大程度的支持并发处理(同时也会带来最大的锁开销)。
3.事务
1.概述
事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎能够成功的对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃
或其它原因无法执行,那么所有的语句都不会查询。也就是说,事务内的语句要么全部执行成功,要么全部执行失败。
事务的ACID特性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)。
原子性:一个事务必须视为一个不可分割的最小工作单元,整个事务的所有操作要么全部提交成功,要么全部失败回滚。
一致性:数据库总是从一个一致性的转台转换到另一个一致性的状态。
隔离性:通常来说,一个事务所做的修改在最终提交以前,对其它事务是不可见的。
持久性:一旦事务提交,则所做的修改就会永久保存到数据库中。
2.隔离级别
隔离级别针对隔离性,隔离性比想象的要复杂。在SQL标准中定义了四种隔离级别,每一种隔离级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。
较低的隔离级别通常可以执行更高的并发。
四种隔离级别:读未提交、读已提交、可重复读、可串行化:
READ UNCOMMITTED(读未提交):事务中的修改,即使没有提交,对其它事务也是可见的。事务可以读取未提交的数据,这也被称为脏读。
READ COMMITTED(读已提交):大多数据库系统默认的隔离级别(MySQL不是)。一个事务开始时,只能看见已经提交的事务所做的修改。这个级别也称为不可重复读,在一个事务内执行两次同样的查询,可能结果不一样。
REPEATABLE READ(可重复读):MySQL默认的隔离级别。解决了脏读的问题,保证了在同一个事务中多次读取同样记录的结果是一致的,但无法解决幻读的问题。InnoDB通过多版本并发引擎控制解决了该问题。
SERIALIZABLE(可串行化):最高的隔离级别。通过强制事务串行执行,避免了幻读。简单来说,SERIALIZABLE会在读取每一行数据上都加锁,所以导致大量的超时和锁争用问题。
3.死锁
死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源或者多个事务同时锁定一个资源时都有可能产生死锁。
解决方法:检测死锁的依赖循环后返回一个错误;当查询时间达到锁等待超时的设定后放弃锁请求。InnoDB处理方法是,将持有最少行级的写锁事务进行回滚。
4.MySQL中的事务
MySQL提供了两种事务型的引擎:InnoDB和NDB Cluster。
InnoDB的两阶段协议锁:在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,需要等事务结束时才释放,这就是两阶段锁协议,分为加锁阶段和解锁阶段,所有的 lock 操作都在 unlock 操作之后。
自动提交(AUTOCOMMIT):MySQL默认采用默认自动提交模式。也就是说如果不是现实地开启一个事务,则每个查询都被当做一个事务执行提交操作。
启用/禁用自动提交模式: SET AUTOCOMMIT = 1;
1或ON表示启用,0或OFF表示禁用。当开启时,所有的查询都在一个事务 中,直到现实地执行COMMIT或者ROLLBACK回滚,该事务结束。
4.多版本并发控制
1.InnoDB
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存行的创建时间,一个保存行的过期时间(删除时间)。当然存储的并不是实际的时间值,而是系统的版本号。
可重复读的隔离级别下的操作过程:
SELECT:1.只查找版本早于当前事务版本(事务开始时刻的系统版本号作为事务的版本号)的数据行;2.行的闪出版本要么没有定义,要么大于当前事务版本号。
INSERT:为新插入的每一行保存当前系统版本。
DELETE:为删除的每一行保存当前系统版本号作为行删除标识。
UPDATE:插入一条新的记录,并保存当前系统版本号作为原来行的删除标识。
5.MySQL的存储引擎
1.概述
使用 show table status;
可以查看表的相关信息。
2.InnoDB
MySQL默认的存储引擎。
InnoDB采用MVCC来支持高并发,实现了四个隔离标准,默认级别是可重复读,并且通过间隙锁策略来防止幻读的出现。
InnoDB基于聚簇索引建立,对主键查询有很高的性能。
InnoDB从磁盘读取数据时采用可预测性预读。能够在内存中创建hash索引以加速读操作的自适应哈希索引。能够加速插入操作的插入缓冲区。支持热备份。
3.MyISAM
MyISAM支持全文索引、压缩、空间函数等,但是不支持事务和行级锁(用表锁),而且崩溃后无法安全恢复。如果数据导入后,不会再进行修改操作,这样的表适合使用MyISAM压缩表,使用压缩表可以减少磁盘空间占用,因此可以减少磁盘IO, 从而齐声查询性能。
4.存储引擎的选择
除非用到某些InnoDB不具备的特性,并且没有其它办法代替,否则都优先选择InnoDB。还有 不到万不得已,不要混合使用多种存储引擎。
事务:要支持事务的优先InnoDB,不需要事务,并且主要是select和insert操作的选MyISAM。
备份:需要热备份的选InnoDB。
崩溃恢复:MyISAM崩溃后发生损坏的概率比InnoDB高很多,而且回复速度也要慢。
只读或者大部分情况下只读的表:读多写少的业务使用MyISAM。
5.修改表的存储引擎
修改语句:alter table tablename engine = InnoDB;