MySQL逻辑架构
并发控制
锁策略
并发处理读或者写时,可以童工两种类型类型的锁系统来解决问题,这两种锁通常被称为:共享锁和排它锁,又称读锁和写锁。
这两个锁的概念是如下的,读锁是共享的,他们是互相不阻塞的两个线程同时读取一个资源的时候,可以互不干扰。写锁是排他的,一个写锁会阻塞其他的读锁和写锁,给定的时间内只能有一个线程执行写入,防止其他用户线程读取别的线程正在写入的数据。
锁粒度
有效提高资源并发访问特定的方式就是尽量锁定更小的数据,而不是所有的资源。在给定的资源上,锁定的数据越小,系统的并发的程度越高,同时加锁也是消耗资源的,获得锁、监察所(锁是否已经解除)释放锁都会增大系统的开销。
MySQL当中有多种存储引擎,每个存储引擎有自己的锁策略和锁粒度。
表锁
表锁是MySQL最基本的锁策略,也是开销最小的策略,他不仅仅是各个存储结构当中实现的锁,更在MySQL的本身(忽略存储引擎的锁机制)定时的锁机制。写锁比读锁有更高的优先级,在一个锁队列当中,一个写锁请求可能会被插入到读锁的前面,反之一个读锁不能插入到写锁的前面。
存储引擎会实现自己的锁策略和锁粒度,但是MySQL本身会有自己的锁机制,而且在某些情况下优先与存储引擎的锁机制而执行,例如:当我们执行ALTER TABLE操作的时候,MySQL实例中会优先使用表锁,忽略存储引擎当中的锁机制。
行级锁
行级锁可以最大程度的支持并发处理,但是同时也带来了最大程度的系统消耗,我们在InnoDB和XtraDB以及一些其他的存储引擎当中实现了行级锁,行级锁只在存储引擎层面来实现,MySQL服务器层面是不实现行级锁的,服务器层对存储引擎的锁机制是完全无感的,所有的存储引擎实现了自己的锁机制。
事务
原子性:所有操作,要么全部成功,要么全部回滚。
隔离性,一个事务所做的的修改的操作,在提交之前对其他的事务都不可见。
就像锁粒度的升级会增加系统的开销一样,事务提供的额外的安全性和数据完成性也会增加系统的开销,一个实现了事务ACID属性的数据库,往往需要更强的CPU,更大的内存,和性能更优越的磁盘:
隔离级别
隔离级别每一级别都定义了一个事务所做的修改,哪些在事务和事务间是可见的,哪些在事务和事务间是不可见的,较低的事务的隔离级别可以执行更高的并发,系统的开销也更低。
在MySQL系统中包几个维度,其中是存储引擎和MySQL服务器,事务是存储引擎层面的东西,有的存储引擎支持事务,有的存储引擎不支持事务,隔离级别是事务与事务间的关系,归根结底还是事务层面的东西,每个存储引擎有自己的锁粒度和锁策略,但是MySQL服务器也有自己的锁策略,比如添加表锁,所以锁不仅仅是存储引擎层面的东西,在MySQL的服务器层面也有他的锁的考虑。
简单的介绍一下系统的隔离级别:
事务的隔离级别:
死锁
死锁一定是有两个或者多个以上的事务共同参与,在某一相同的资源上互相争抢(一个事务已经获得,另一个事务想要争抢)也就是请求锁定对应已经占用的资源,从而导致恶性循环的现象,举例如下:
加入兰格事务都执行了第一条update语句,那么两个事务处理的行上分别加上的行锁,当两个事务分别执行第二条的时候,尝试获取占用对方的资源,就会等待对方释放锁,而两者又都持有对方需要的锁,这就是死锁,除非外部介入,否则才能解除死锁。
数据库系统实现了四所检测和死锁超时机制,InnoDB存储引擎可以检测到死锁的循环依赖,检测到之后会立即返回一个错误,然后InnoDB的解决死锁的方式是,将一个持有最少量锁的事务进行回滚,这是性对比较简单的死锁回滚算法。死锁的产生有双重原因:有的是真的是因为数据的冲突,有的则是因为存储引擎的实现方式的导致的。死锁发生之后,只有部分或者完全回滚其中的一个事务才能打破死锁(说白了就是将弱势事务占用的焦点资源进行释放)
事务日志
事务日志可以提高事务的效率,使用事务日志,存储引擎在修改表的数据的时候只需要将修改其内存拷贝,再讲修改行记录持久化到磁盘的事务日志中,而不是直接将数据持久到磁盘。
事务日志采用的事追加的方式,写事务日志的方式是将磁盘上的一小块区域进行顺序IO,顺序IO不像随机IO一样在磁盘上移动探头,所以采用事务日志的方式要快的多,事务日志持久化之后,内存中被修改的数据在后台可以慢慢的刷回到磁盘中,我们称这种方式叫做预写式日志,修改数据需要进行两次写盘操作。
MySQL中的事务
MySQL官方提供的支持事务的存储引擎
InnoDB、NDB Cluster
第三方的提供支持事物存储引擎
XtraDB、PBXT
自动提交
MySQL采用自动提交模式,如果不是显示的开始一个事务,每个查询都会被当做个是一个事物来执行。
如何查看和改变MySQL自动提交行为
show variables like 'autocommit'; 1或者on表示启用,0或者off表示禁用。
当我们关闭自动提交之后,所有的查询操作都是在一个事务中,只有当我们显示的commit或者Rollback的时候改事务才能够结束,同时也开启了一个新的事务。自动提交值的修改对于非事务的存储引擎来讲是无感的,疑问人家根本不支持事务,对这玩意也无感。
哪些操作会强制执行commit提交当前事务的?
对于一些DDL语言,也就是数据库定义语言,他们是变更表结构会导致大量数据更新的语言,比如ALTER TABLE语句就会给表加上表锁,以及LOCK TABLES也会导致同样的结果,在执行这些SQL之前会强制提交前面的SQL语句,如果是自动提交的话,会等待所有的事务commit之后在执行。
set session isolation level read committed 我们可以通过这样的SQL来修改当前会话的隔离级别
我们可以在配置文件中设置整个数据库的隔离级别。
在事务中混合使用存储引擎会怎样?
事务并不是由MySQL服务器管理的,而是由下层的存储引擎来实现的,同一个事务中,使用有多张不同存储引擎的表时不可靠的。
在这种情况下,如果事务发生了回滚,非事务型的表的变更就不会发生回滚,在非事务型的表上执行事务相关操作的时候,别的时候没啥,回滚的时候会发出一个警告,非事务型的表上的变更不会进行回滚。
什么是隐式锁定什么是显示锁定?
InnoDB采用的是两阶段锁定协议,在事务执行过程中随时可以执行锁定,锁只有在回滚或者事务提交的会后才会全部被释放,也就是只有当事务结束,事务获取的全部的锁才会被释放,前面描述的都是隐式加锁的方式,InnoDB会根据隔离级别在需要的时候进行加锁,也就是存储引擎的加锁行为是根据隔离级别来决定的。
InnoDB也支持通过特定的语句进行显示的锁定
SELECT ... LOCK IN SHADE MODE SELECT ... FOR UPDATE
MySQL服务器也支持 LOCK TALBES 和 UNLOCK TABLES 这样的语句这是在服务层实现的,与存储引擎无关,尽量任何时候都不要显示的加锁,存储引擎的锁机制工作的很好。
多版本并发控制
MySQL事务型存储引擎是实现的都不是简单的行级锁,基于提升并发性的考虑,他们一般实现了多版本并发控制也就是(MVCC)各种数据库的事务引擎基本上都实现了多版本的并发控制,各自实现机制不同,因为没有一个统一的MVCC标准。
可以简单的认为MVCC是行级锁的一个变种,很多情况下避免了加锁操作,大多都实现了非阻塞的读操作,写操作也只锁定必要的行。
MySQL的存储引擎
查看表的状态
我们可以通过下列的语句查看所得状态
show table status like 'user';
**
**
InnoDB存储引擎
InnoDB数据存储在表空间,表空间是由InnoDB管理的黑盒子,有一些列的数据文件组成。InnoDB可以将每个表的数据和索引存放在单独的文件中。
InnoDB采用MVCC来支持并发事务控制,实现了四个标准的隔离级别,默认的隔离级别是REPEATABLE READ不可重复读,并且通过间隙锁策略来实现幻读的产生,间隙锁是的InnoDB不仅仅锁定查询设计的行,还会对索引中的间隙进行锁定,防止幻影行的插入。
InnoDB表时基于聚簇索引简历的,InnoDB的索引结构和MySQL的其他引擎有很大的不同,聚簇索引对主键查询有很高的性能,不过他的二级索引,也就是非主键索引,中必须包含主键列,所以主键列特别大的话,其他的索引也会非常的大,若表上的索引较多的话,主键应该尽可能的小。
MyISAM存储引擎
MyISAM提供了大量的特性,包括全文索引、压缩、空间函数等,MyISAM不支持事务和行级锁,崩溃后无法安全恢复
MyISAM会将表存储在两个文件中,数据文件和索引文件,分别以.MYD和.MYI作为拓展名MyISAM可以包含动态行或者静态行(长度固定)MyISAM宝可以存储行记录数,MySQL会根据报的定义来决定采取哪种格式,
MyISAM如果宝石边长行,默认配置只能处理256TB的数据,这是由于执行数据记录的指针为6个字节,我们可以支持8字节的指针,改下配置即可。
MyISAM有什么特性?
加锁和并发:MyISAM对整张表进行加锁,而不是针对行,读取时会对需要督导的所有表加共享锁,写入是则对表加排它锁。
索引特性:对于MyISAM表,即使是BLOB和TEXT等长字段,也可以基于钱500字创建索引。
延迟更新索引键
创建MyISAM表的时候,如果指定了DELAY_KEY_WRITE选项,在每次修改执行完成时不会立即将修改的索引数据写入磁盘,而是会写到内存中的缓冲区,只有在清理键缓冲区或者关闭博爱的时候才会架构对应的索引快写入到磁盘中。这种方式极大的提升了写入性能。此特性可以全局设置,也可以单个表进行设置。