Fork me on GitHub

《高性能Mysql》第一章、Mysql架构与历史

Mysql逻辑架构

连接管理与安全性

每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行,该线程只能轮流在某个CPU核心或者CPU中运行。服务器会负责缓存线程,因此不需要为每一个新建的连接创建或者销毁线程。

当客户端(应用)连接到Mysql服务器时,服务器需要对其进行认证。认证基于用户名、原始主机信息和密码。一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限。

优化与执行

Mysql会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询、决定表的查询顺序,以及选择合适的索引等。

对于Select语句,在解析查询之前,服务器会先检查查询缓存,如果能够在其中找到对应的查询,服务器就不必再执行查询解析、优化和执行的整个过程,而是直接返回查询缓存中的结果集。

并发控制

读写锁

读锁是共享的,或者说是相互不阻塞的。写锁是排他的,也就是说一个写锁会阻塞其他的写锁和读锁。

在实际的数据库系统中,每时每刻都在发生锁定,当某个用户在修改某一部分数据时,Mysql会通过锁定防止其他用户读取同一数据。大多数时候,Mysql锁的内部管理都是透明的。

锁粒度

在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之间不发生冲突即可。

表锁

表锁是Mysql中最基本的锁策略,并且是开销最小的策略。它会锁住整张表。

行级锁

行级锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。行级锁只在存储引擎层实现,而Mysql服务器层没有实现。服务器层完全不了解存储引擎中的锁实现。

事务

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。

ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。

隔离级别

隔离级别脏读可能性不可重复读可能性幻读可能性加锁读
READ UNCOMMITTEDYESYESYESNO
READ COMMITTEDNOYESYESNO
REPEATABLE READNONOYESNO
SERIALIZABLENONONOYES

死锁

死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。

为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时机制。InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。

事务日志

事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久化到磁盘。事务日志采用的是追加的方式,事务日志持久化以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志,修改数据需要写两次磁盘。

如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写会磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。

Mysql中的事务

Mysql提供了两种事务型的存储引擎:InnoDBNDB Cluster

自动提交 (AUTOCOMMIT)

Mysql默认采用自动提交模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当做一个事务执行提交操作。

多版本并发控制 (MVCC)

MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。

MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。

MVCC只在REPEATABLE READREAD 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
2
3
mysql> CREATE TABLE innodb_table LIKE myisam_table;
mysql> ALTER TABLE innodb_table ENGINE=InnoDB;
mysql> INSERT INTO innodb_table SELECT * FROM myisam_table;
求鼓励,求支持!