MySQL架构与历史
MySQL存储引擎架构的设计将查询处理及其他系统任务的存储/提取相分离;
1.1 MySQL逻辑架构
逻辑架构分三层:
-
最上层:该层服务并非MySQL独有,大多数基于网络的客户端/服务器的工具或服务器都有的架构;
-
中间层:多数MySQL核心服务功能存在的一层,包括解析、分析、优化、缓存以及所有的内置函数等;
-
最底层:包含了存储引擎,负责组织MySQL中数据的存储与提取;
MySQL会解析查询,并创建内部数据结构(解析树),然后对齐进行各种优化,包括重写查询、决定表读取顺序,以及选择合适的索引等;
1.2 并发控制
“读锁”也被称为"共享锁",“写锁”被称为“排他锁”;
锁的概念:
-
读锁是共享的,互相不阻塞的,多个客户在同一时刻可以同时读取同一个资源而互不干扰;
-
写锁是排他的,即一个写锁会阻塞其他的写锁和读锁;
锁粒度:
-
一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源;最理想的方式,只对需要修改的数据片进行精确的锁定;任何时候,在给定的资源上,锁定的数据量越少,系统的并发程度越高。
-
每种MySQL存储引擎都可以实现自己的锁策略和锁粒度;
表锁:
-
表锁是MySQL中最基本的锁策略,并且是开销最小的策略;
行级锁:
-
行级锁可以最大程度的支持并发处理(同时锁开销也最大);
-
行级锁只在存储引擎层实现,而MySQL服务器层没有实现;
1.3 事物(ACID特性):
-
事物就是组原子性的SQL查询(独立的工作单元);
-
原子性:一个事物必须被视为一个不可分割的最小工作单元,整个事物中的所有操作要么全部执行完毕并提交,要么全部失败回滚;
-
一致性:数据库总是从一个一致性的状态转换到另外一个一致性的状态;
-
隔离性:通常来说,一个事物在所做的修改在最终提交之前,对其他事物是不可见的;
-
持久性:一旦事物提交,则其所做的修改就会永久保存到数据库中;
隔离级别:
-
READ UNCOMMITED(未提交读):在该隔离级别中,事物中的修改,即使没有提交,也对其他事物是可见的;其他事物可以读取未提交的数据,称为脏读;
-
READ COMMITED(提交读):大多数数据库系统的默认隔离级别都是READ COMMITED(但MySQL不是),该隔离级别中事物对数据的修改在提交之前对其他事物不可见,即能够避免“脏读”;但该隔离级别可能会遇到“不可重复读”的问题,即两次执行同样的查询,可能会得到不一样的结果;
-
REPEATABLE READ(可重复读):该隔离级别解决了不可重复读以及脏读的问题,保证了在同一个事物中多次读取同样记录的结果是一致的;但该级别无法解决幻读问题,指的是当某个事物在读取某个范围内的记录时,另外一个事物又在该范围内插入了新的记录,当之前的事物再次读取该范围的记录时,会产型幻行。 InnoDB和XtraDB存储引擎通过MVCC解决幻读问题;
-
SERIALIZABLE(可串行化):是最高高的隔离级别;通过强制事物串行执行,避免了“幻读”问题;
死锁
-
死锁指两个或者多个事物在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事物试图以不同的顺序锁定资源时,就可能会产生死锁;多个事物同时锁定同一个资源时,也会产生死锁;
-
解决方案:
-
越复杂的系统,如InnoDB存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误;
-
当查询的时间达到锁等待超时的设定后放弃锁请求;
-
InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事物进行回滚(相对较为简单的死锁回滚算法)。
-
-
锁的行为与顺序是和存储引擎相关的。以同样的顺序执行语句,有些存储引擎会产生死锁,有些则不会;死锁的产生有双重原因:有些是因为真正的数据冲突(这种情况通常很难避免),有些则完全由于存储引擎的实现方式导致。
事物日志:
-
事物日志可以帮助提高事物的效率;
-
使用事物日志,存储引擎在修改表的数据时只需要修改其内存拷贝,在将该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘;
MySQL中的事物
-
MySQL提供了两种事物型的存储引擎:InnoDB和NDB Cluster
-
自动提交(AUTOCOMMIT)
-
MySQL默认采用自动提交模式(AUTOCOMMIT)。即就是说,若不是显示地开始一个事物,则每个查询都被当做一个事物执行提交操作;
-
在当前连接中,可以通过设置AUTOCOMMIT变量来启用或则禁止自动提交模式:SET AUTOCOMMIT = 1(开启);1 或者 ON 表示启用,0 或者 OFF 表示禁用;
-
当AUTOCOMMIT = 0 时,所有的查询都在一个事物中进行,直到显示地执行COMMIT提交或者ROLLBACK回滚,该事物才会结束,同时又开始一个新事物。
-
修改AUTOCOMMIT就对非事物型的表,如MYISAM或者内存表,不会有任何影响,对该类表来说,没有COMMIT和ROLLBACK概念,也可以说是一直处于AUTOCOMMIT启用的模式;
-
还有一些命令,在执行之前会强制执行COMMIT提交当前的活动事物。如在DDL中,导致大量数据改变的操作,如ALTER TABLE等;
-
MySQL可以通过执行SET TRANSCATION ISOLATION LEVEL 命令来执行隔离级别。
-
-
在事物中混合使用存储引擎
-
MySQL服务器层不管理事物,事物是由下层的存储引擎实现的。在同一个事物中,使用多种存储引擎是不可靠的。
-
-
隐式和显式锁定
-
InooDB采用的是阶段锁定协议;
-
隐式锁定:在事物执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或者ROLLBACK的时候才会被释放,并且所有的锁是在同一时刻被释放。
-
显式锁定:InnoDB层支持特定的语句进行显式锁定,这些语句不属于SQL规范(应尽量避免使用)
-
SELECT ... LOCK IN SHARE MODE
-
SELECT ... FOR UPDATE
-
-
MySQL也支持LOCK TABLES 和 UNLOCK TABLES 语句,这是在服务器层实现的,与存储引擎无关;
-
LOCK TABLES和事物之间相互影响在某些版本中可能会产生无法预料的结果; 除了事物中禁用AUTOCOMMIT可以使用LOCK TABLES之外,其他任何情况都不要显式地执行LOCK TABLES,不管使用的是什么存储引擎;
-
1.4 多版本并发控制(MVCC)
-
可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行;
-
MVCC的实现,是通过保存数据在某个时间点的快照来实现的。(即不关需要执行多长时间,每个事物看到的数据都是一致的。根据事物开始的时间不同,每个事物对同一张表,同一时刻看到的数据可能是不一样的。)
-
不同存储引擎的MVCC实现各有不同,分为乐观并发控制和悲观并发控制
-
InnoDB的MVCC:通过在每行记录后面保存两个隐藏的列来实现;一个保存了行的创建时间,一个保存行的过期时间(该时间并发真正的时间值,而是系统版本号)。每开始一个新的事物,系统版本号都会递增;事物开始时刻的系统版本号会作为事物的版本号,用来和查询到的每行记录的版本号进行比较;
-
SELECT:InnoDB只查找版本号早于当前事务版本的数据(即行的开始时间在当前事物版本之前);行的删除版本要么未定义,要么大于当前事务的版本号。<只有复合以上两个条件的记录,才能作为查询结果返回>
-
INSERT:InnoDB为新插入的每一行记录保存当前版本号作为行版本号;
-
DELETE:InnoDB未删除的每一行保存当前系统版本号作为行删除标识;
-
UPDATE:InnoDB为插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识;
-
1.5 MySQL的存储引擎
InnoDB存储引擎:
-
InnoDB是MySQL的默认事物型存储引擎;
-
InnoDB的数据存储在表空间中,表空间是由InnoDB管理的一个黑盒子,由一系列的数据文件组成。
-
InnoDB采用MVCC来支持高并发,并且实现了四个标准的隔离级别;
-
InnoDB表时基于聚簇索引建立的;聚簇索引对主键查询有很高的性能。不过它的二级锁索引(非主键索引)中必须包含主键列;
-
InnoDB内部做了很多优化,包括从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应哈希索引,以及能够加速插入操作的插入缓冲区等;
MyISAM存储引擎
-
在MySQL 5.1及之前的版本中,MyISAM是默认的存储引擎;
-
不支持事物、行级锁,以及崩溃后无法安全恢复数据;
-
存储:
-
MyISAM会将表存储在两个文件中:数据文件(.MYD)、索引文件(.MYI)
-
MyISAM表可以包动态或者静态(长度固定)的行;MySQL会根据表的定义来决定采用何种行格式;MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间;
-
-
MyISAM特性:
-
加锁与并发:MyISAM对整张表加锁,而不是针对行。读取时会对需要读到的所有表加共享锁,写入时对表加排他锁,但是在表有读取查询的同时,也可以往表中插入新的记录(被称为并发插入);
-
修复:对于MyISAM表,MySQL可实现手工或者自动执行检查和修复操作(并非崩溃后恢复);而且执行表的修复可能会导致一些数据的丢失,而且修复的操作非常慢;可通过CHECK TABLE xxx 检查表的错误,若有错误可通过REPAIR TABLE xxx 进行修复;
-
索引特性:支持全文索引
-
延迟更新索引键:创建MyISAM表时,若指定了DELAY_KEY_WRITE选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是回写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。
-
-
MyISAM压缩表:
-
若表在创建并导入数据以后,不会再进行修改操作,那么这样的表或许适合采用MyISAM压缩表;
-
可以使用myisampack对MyISAM表进行压缩(也叫做打包);压缩表是不能进行修改的(除非先将压缩过的表进行解压,修改后再次压缩)
-
压缩表也支持索引,但索引也是只读的;
-
压缩时表中的记录是独立压缩的,所以读取单行的时候不需要解压整张表;
-
-
MySQL内建的其他存储引擎:
-
Archive引擎:只支持SELECT 和 INSERT 操作,在MySQL 5.1之前也不支持索引;该引擎会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘I/O更少;但是每次SELECT查询都需要执行全表扫描,所以Archive表适合日志和数据采集类应用;支持行级锁和专用的缓冲区,可实现高并发插入;
-
Blackhole引擎:该引擎没有实现任何存储机制,会丢其所有插入的数据,而不做任何保存
-
CSC引擎:该引擎可以将普通的CSV文件作为MySQL的表来处理,但不支持索引
-
Federated引擎:该引擎是访问其他MySQL服务器的一个代理;
-
Memory引擎:Memory表支持Hash索引,查找操作非常快;Memory表是表级锁,并发写入性能较低;不支持BLOB或TEXT类型的列,并且每行的长度是固定的;若MySQL在执行过程中需要使用临时表来保存中间结果,内部使用的临时表就是Memory表,若中间结果太大超出了Memory表的限制,或者包含BLOB或TEXT字段,则临时表会转换成MyISAM表;(临时表只在单个连接中可见,当连接断开时,临时表也将不复存在);
-
-
选择合适的引擎
-
除非需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该优先选择InnoDB引擎;
-