StarkerSong Get Busy Living

MySQL数据库(1)-MySQL架构和历史

2016-09-29

MySQL逻辑架构

MySQL存储引擎架构的设计将查询处理及其他系统任务数据的存储/提取相分离。将处理和存储分离的设计可以在使用时根据性能、特性,以及其他需求选择数据存储的方式。

连接管理与安全性

客户端连接在服务器中拥有线程,连接的查询只会在单独的线程中执行,线程只能轮流在某个CPU核心或者CPU中运行。服务器会负责缓存线程,不需要为每个新建的连接创建或者销毁线程。客户端连接到MySQL服务器时,服务器需要基于用户名、原始主机信息和密码进行认证。连接成功后,还需验证客户端是否具有执行某个特定的查询权限。

优化和执行

MySQL会解析查询,井创建内部数据结构(解析树) ,然后对其进行各种优化,包括重写查询、决定表的读取顺序,以及选择合适的索引等。用户可以通过以下方式提高运行效率:

  • 特殊关键字提示(hint)优化器,影响决策过程。
  • 请求优化器解释(explain)优化过程的各个因素,使用户知道服务器优化决策的步骤,提供参考基准,便于用户重构查询和schema、修改相关配置。

并发控制

在数据库中通过并发控制,在处理并发读写,通过共享锁排它锁解决数据不一致性问题。

  • 共享锁(读锁):多个客户在同一时刻同时读取相同资源,而互不干扰。
  • 排它锁(写锁):排它锁会阻塞其他的写和读。

让锁定对象更有选择性,提高共享资源并发性,尽量锁定需要修改的部分数据而不是所有资源。在任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互间不发生冲突即可。

锁的各种操作,包括获得锁、检查锁是否已经解除、释放锁等,都会增加系统的开销。如果系统花费大量的时间来管理锁,而不是存取数据,系统性能可能会受影响。

锁的策略在锁的开销和数据的安全性之间寻求平衡,一般在表上施加行级锁,并以各种复杂的方式来实现。

  • 表锁:表锁是MySQL中最基本的锁策略,并且是开销最小的策略。写锁阻塞读写操作,读锁互不阻塞。写锁比读锁有更高优先级。
  • 行级锁:最大程度支持并发处理(同时带来最大锁开销)。

事务

事务是一个独立的工作单元,事务内的语句,要么全部执行,要么全部不执行。

  • 原子性:事务是不可分割的最小工作单元,要么全部提交成功,要么全部失败回滚。
  • 一致性:从一个一致性的状态转换到另外一个一致性状态。
  • 隔离性:一个事务所做的修改在最终提交之前,对其他事务是不可见的。
  • 持久性:一旦事务提交,则其所做的修改会永久保存到数据库中。

锁的粒度增加系统开销,实现ACID特性的数据库通常会需要更强的CPU处理能力、更大的内存和更多的磁盘空间。

隔离级别

Read Uncommitted(未提交读)

事务中的修改,即使没有提交,对其他事务也是可见的。读取未提交的数据成为脏读

Read Committed(提交读)

大多数数据库系统的默认级别都是Read Committed(MySQL不是)。一个事务从开始到提交前,所做的任何修改对其他事务都是不可见的。执行两次相同查询,可能得到不同结果。这个级别也叫不可重复读

Repeatable Read(可重复读)

解决了脏读,保证多次读取同样记录结果一致,但是无法解决幻读,即当某个事务在读取某个范围内的记录时,另一个事务又在该范围内插入新的记录,当之前的事务再次读取该范围的记录时,会产生幻行

Serializable(可串行化)

最高的隔离级别,通过强制事务串行执行,避免幻读问题。Serializable会在读取的每行数据上都加上锁,所以可能导致大量的超时和锁争用问题。

脏读:一个事务读取到了另外一个事务没有提交的数据; 如:事务T1更新了一行记录的内容,但是并没有提交所做的修改。事务T2读取到了T1更新后的行,然后T1执行回滚操作,取消了刚才所做的修改。现在T2所读取的行就无效了;

不可重复读:在同一事务中,两次读取同一数据,得到内容不同; 如:事务T1读取一行记录,紧接着事务T2修改了T1刚才读取的那一行记录。然后T1又再次读取这行记录,发现与刚才读取的结果不同。这就称为“不可重复”读,因为T1原来读取的那行记录已经发生了变化;

幻读:同一事务中,用同样的操作读取两次,得到的记录数不相同; 如:事务T1读取一条指定的WHERE子句所返回的结果集。然后事务T2新插入 一行记录,这行记录恰好可以满足T1所使用的查询条件中的WHERE子句的条件。然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突然出现的一样。 隔离级别越低,事务请求的锁越少或保持锁的时间就越短。InnoDB存储引擎默认的支持隔离级别是REPEATABLE READ。

死锁

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

  • 死锁检测 检测到死锁的循环依赖,并立即返回一个错误。
  • 死锁超时机制查询的时间达到锁等待超时的设定后放弃锁请求。

死锁发生后,只有部分或者完全回滚其中一个事务才能打破死锁。

事务日志

使用事务日志,存储引擎在修改表的数据时,只需要修改其内存拷贝,再把修改行为记录到持久化的硬盘事务日志中,无需每次修改数据本身持久到磁盘。事务日志持久化后,内存中被修改的数据在后台慢慢地刷回到磁盘。通常称为预写式日志,修改数据需要写两次磁盘。

事务日志,采用追加的方式,写日志的操作是磁盘上一小块区域内的顺序I/O,不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快的多。

多版本并发控制 MVCC

大多数事务型存储引擎实现的都不是简单的行级锁,在很多情况下避免了加锁操作,因此MVCC开销更低。基于提升并发性的考虑,一般同时实现多版本并发控制(MVCC)。

InnoDB的MVCC,通过在每行记录后面保存两个隐藏的列(创建时间、删除时间列)来实现。不过存储的并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本会自动递增。事务开始的版本号作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

参考资料

  • 《高性能MySQL》

Similar Posts

Comments