Mysql逻辑架构
连接管理与安全性
每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行,该线程只能轮流在某个CPU核心或者CPU中运行。服务器会负责缓存线程,因此不需要为每一个新建的连接创建或者销毁线程。
当客户端(应用)连接到Mysql服务器时,服务器需要对其进行认证。认证基于用户名、原始主机信息和密码。一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限。
优化与执行
Mysql会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询、决定表的查询顺序,以及选择合适的索引等。
对于Select语句,在解析查询之前,服务器会先检查查询缓存,如果能够在其中找到对应的查询,服务器就不必再执行查询解析、优化和执行的整个过程,而是直接返回查询缓存中的结果集。
并发控制
读写锁
读锁是共享的,或者说是相互不阻塞的。写锁是排他的,也就是说一个写锁会阻塞其他的写锁和读锁。
在实际的数据库系统中,每时每刻都在发生锁定,当某个用户在修改某一部分数据时,Mysql会通过锁定防止其他用户读取同一数据。大多数时候,Mysql锁的内部管理都是透明的。
锁粒度
在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之间不发生冲突即可。
表锁
表锁是Mysql中最基本的锁策略,并且是开销最小的策略。它会锁住整张表。
行级锁
行级锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。行级锁只在存储引擎层实现,而Mysql服务器层没有实现。服务器层完全不了解存储引擎中的锁实现。
事务
事务就是一组原子性的SQL查询,或者说一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。
ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。
隔离级别
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
---|---|---|---|---|
READ UNCOMMITTED | YES | YES | YES | NO |
READ COMMITTED | NO | YES | YES | NO |
REPEATABLE READ | NO | NO | YES | NO |
SERIALIZABLE | NO | NO | NO | YES |
死锁
死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。
为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时机制。InnoDB
目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。
事务日志
事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久化到磁盘。事务日志采用的是追加的方式,事务日志持久化以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志,修改数据需要写两次磁盘。
如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写会磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。
Mysql中的事务
Mysql提供了两种事务型的存储引擎:InnoDB
和NDB Cluster
。
自动提交 (AUTOCOMMIT)
Mysql默认采用自动提交模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当做一个事务执行提交操作。
多版本并发控制 (MVCC)
MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
MVCC只在REPEATABLE READ
和READ COMMITED
两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITED
总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE
则会对所有读取的行都加锁。
Mysql的存储引擎
可以使用SHOW TABLE STATUS
命令显示表的相关信息(在Mysql 5.0以后的版本中,也可以查询INFORMATION_SCHEMA
中对应的表)。
InnoDB存储引擎
InnoDB
是Mysql的默认事务型引擎,也是最重要、使用最广泛的存储引擎。
MyISAM存储引擎
MyISAM
提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM
不支持事务和行级锁,而且有一个缺陷是崩溃后无法安全恢复。
对于只读的数据,或者表比较小、可以忍受修复操作,则依然可以继续使用MyISAM
。
选择合适的存储引擎
除非需要用到某些InnoDB
不具备的特性,并且没有其他办法可以替代,否则都应该优先选择InnoDB
引擎。
转换表的引擎
有多种方法可以将表的存储引擎转换成另外一种引擎,每种方法都有其优缺点。如果转换表的存储引擎,将会失去和原引擎相关的所有特性。
- ALTER TABLE
下面的语句将mytable的引擎修改为InnoDB
:
1 | mysql> ALTER TABLE mytable ENGINE = InnoDB; |
上述语法可以适用于任何存储引擎,但是需要执行很长时间。
- 导入与导出
使用mysqldump
工具将数据导出到文件,然后修改文件中CREATE TABLE
语句的存储引擎选项。
- 创建和查询(CREATE和SELECT)
先创建一个新的存储引擎表,然后利用INSERT...SELECT
语法来导数据:
1 | mysql> CREATE TABLE innodb_table LIKE myisam_table; |