《第一章:mysql 架构历史》
mysql 足够灵活,能够适应高要求的环境。如web 类应用。 MySQL既可以嵌入到应用程序中,也可以支持数据仓库,内容索引和部署软件,高可用的冗余系统,在线事务处理系统OLTP等各种应用类型。
每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询
只会在这个单独的线程中执行,该线程只能轮流在某个CPU核心或者CPU中运行。服务器会负责缓存线程,因此不需要为每一个新建的连接创建或者销毁线程。
当客户端连接到MySQL服务器时,服务器需要对其进行认证,认证基于用户名,原始主机信息和密码。如果使用了安全套接字SSL的方式连接,还可以使用X.509证书认证。一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限。
优化与执行:mysql 会解析查询,并创建内部数据结构,然后对其进行各种优化,包括重写查询,决定表的读取顺序,以及选择合适的索引等。用户可以通过特殊的关键字提示 hint 优化器,影响它的决策过程。也可以请求优化器解释 explain 优化过程的各个因素,使用户可以知道服务器是如何进行优化决策的,并提供一个参考基准,便于用户重构查询和schema,修改相关配置,使应用尽可能高效运行。
优化器不关心表使用的是什么存储引擎,但存储引擎对于优化查询是有影响的。对于select 语句,解析查询之前,服务器会先检查查询缓存query cache,如果能够在其中找到对应的查询,服务器就不必再执行查询解析,优化,执行的整个过程,而是直接返回查询缓存中的结果集。
并发控制: | 只要有多个查询需要在同一时刻修改数据,都会产生并发控制的问题。 |
mysql 在两个层面做并发控制: | 服务器层与存储引擎层。 |
读写锁: | 解决并发问题,可以通过实现一个由两种类型的锁组成的锁来解决问题,这两种类型的锁称为共享锁shared lock和排他锁 exclusive lock,也叫读锁 read lock和写锁 write lock。 |
读锁: | 读锁是共享的,相互不阻塞。多个客户在同一时刻可以同时读取同一个资源,而互不干扰。 |
写锁 | 写锁是排他的,一个写锁会阻塞其他的写锁和读锁,出于安全策略,只有这样,才能保证在给定的时间里,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源。 |
锁粒度: | 一种提高共享资源并发性的方式就是让锁定对象更有选择性,尽量只锁定需要修改的部分数据,而不是全部资源。或者只对修改的数据片进行精确的锁定,锁定的数据量越少,系统的并发程度越高。 |
存在问题: | 加锁需要消耗资源。锁的各种操作,包括获得锁,检查锁是否已经解除,释放锁等,都会增加系统的开销。需要在锁的开销和数据的安全性之间寻求平衡[一般都是在表上施加行级锁比较好]。 |
MySQL提供多种选择。每种存储引擎都可以实现自己的锁策略和锁粒度。在存储引擎的设计中,锁管理是个非常重要的决定,将锁粒度固定在某个级别,可以为某些特定的应用场景提供更好的性能,但同时也会失去另外的一些应用场景的良好支持。
表锁table lock : | 表锁是mysql 中最基本的锁策略,并且是开销最小的策略。它会锁定整张表,一个用户在对表进行写操作前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。只有没有写锁时,其他读取的用户才能获得读锁,读锁之间是不相互阻塞的。
注解:服务器会为alter table 之类的语句使用表锁。 |
行级锁 row lock : | 行级锁可以最大程度的支持并发处理(最大的锁开销)。InnoDB 和 XtraDB ,以及其他一些存储引擎中实现了行级锁。行级锁只在存储引擎层实现,MySQL 服务层没有实现。 |
事务:事务内的语句,要么全部执行成功,要么全部执行失败。
名字 | 解释 |
1.原子性atomicity : | 一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,一个事务,不可能只执行其中一部分操作,这就是事务的原子性 |
2.一致性consistency : | 数据库总是从一个一致性的状态转换到另外一个一致性的状态。 |
3.隔离性isolation : | 一个事务所做的修改在最终提交之前,对其他事务都是不可见的。 |
4.持久性durability : | 一旦事务提交,则其所做的修改就会永久保存到数据库中。就算系统崩溃,数据也不会丢失 |
1.read uncommitted 未提交读: | 在read uncommitted 级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,会造成脏读dirty read。比起其他隔离级别好处不会太多,但问题不少,所以实际应用中一般很少使用。 |
2.read commited 提交读: | 大多数数据库系统的默认级别都是read commited,一个事务开始时只能看见已经提交的事务所做的修改。也称为不可重复读。 |
3.repeatable read 可重复读: | repeatable read 解决了脏读问题,保证了在 同一个事务中多次读取同样的记录的结果是一样的。可重复度级别无法解决幻读问题。[当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行 phantom row],InnoDB 和XtraDB 存储引擎通过多版本并发控制(MVCC )解决了幻读问题。 |
4.serializable 可串行化: | serializable 是最高的隔离级别。它通过强制事务串行执行,避免了幻读问题。serializable 会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁竞争的问题。实际开发中很少用。 |
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
read uncommitted | yes | yes | yes | no |
read commited | no | yes | yes | no |
repeatable read | no | no | yes | no |
serializable | no | no | no | yes |
死锁:死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,也会产生死锁。
1.为了解决死锁,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,InnoDB存储引擎,越能检测到死锁 的循环依赖,并立即返回一个错误。解决方式很有效,否则死锁会导致出现慢查询。 |
2.当查询的时候达到锁等待超时的设定后放弃锁请求,这种方式不太好。 |
3.InnoDB 处理死锁的方式是,将持有最少行级排他锁的事务进行回滚。 |
锁的行为和顺序是和存储引擎相关的。
死锁产生有双重原因:
1.有些是因为真正的数据冲突,这些情况通常很难避免。 |
2.有些则由于存储引擎的实现方式导致的。 |
注解:死锁发生后,只有部分或者全部回滚其中一个事务,才能打破死锁。 |
事务日志的作用:事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不是每次都将修改的数据本身持久到磁盘。
事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序I/O,而不像随机I/O 需要在磁盘的多个地方移动刺头,所以采用事务日志的方式相对很快。事务日志持久以后,内存中被修改的数据在后台可以慢慢的刷回到磁盘,大多数存储引擎也是这样实现,称为写式日志write-aheadLogging。
mysql 中的事务:
mysql提供了两种事务型的存储引擎:InnoDB 和 NDB Cluster。还有一些第三方存储引擎也支持事务,比如XtraDB 和PBXT。
自动提交auto commit : mysql 默认采用自动提交模式。
mysql 可以通过set transaction isolation level 命令设置隔离级别,新的隔离级别会在下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以只改变当前会话的隔离级别&#x