MySQL逻辑架构
连接/线程管理
- 每个客户端都会在服务器进程中拥有一个线程,该连接的查询只会在这个单独的线程中执行。
- 服务器对线程进行缓存,不需要为每一个新建的连接创建或销毁线程。
- 客户端连接到MySQL服务器时,需要对其进行认证
优化与执行
- 检查查询缓存
- 解析查询
- 创建解析树
- 优化:重写查询、决定表的读取顺序
- 选择合适的索引
并发控制
- 多个查询需要在同一时刻修改数据,产生并发控制的问题
读写锁
- 在处理并发读或写时,可以通过实现一个由两种类型的锁组成的锁系统来解决问题。这两种类型的锁通常被称为共享锁(shared lock)和排他锁(exclusive lock),也叫读锁(read lock)和写锁(write lock)。
- 读锁是共享的,多个客户在同一时刻可以同时读取同一个资源,互不干扰。
- 写锁是排他的,一个写锁会阻塞其他的写锁和读锁。确保在给定时间内,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源。
锁粒度
- 提高共享资源并发性的方式是让锁定对象更有选择。任何时候,在给定的资源上,锁定的数据量越少,系统的并发程度越高
- 加锁需要消耗资源
- 锁策略,就是在锁的开销和数据的安全性之间寻求平衡。大多数商业数据库采用的是在表上施加行级锁
两个重要的锁策略
表锁(table lock)
- 最基本的锁策略,开销最小的策略
- 一个用户在对表进行写操作前,需要获得写锁,这会阻塞其他用户对该表的所有读写操作。
行级锁(row lock)
- 最大程度地支持并发处理,同时也带来了最大的锁开销
- 只在存储引擎层实现
事务
事务指的是一组原子性的SQL查询,或者说是一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。
ACID
- 原子性(atomicity),一个事务必须要被视为一个不可分割的最小工作单元,整个事务中的所有操作要么提交成功,要么全部失败回滚,对于一个事务来说不可能只执行其中一部分
- 一致性(consitency),数据库总是从一个一致性的状态转移到另外一个一致性的状态。
- 隔离性(isolation),一个事务所做的修改在最终提交之前,对其他事务是不可见的。
- 持久性(durability),一旦事务提交后,其所做的修改就会永久保存到数据库中,即使系统崩溃,修改的数据也不会丢失。
隔离级别
- READ UNCOMMITTED(未提交读)
- 事务中的修改,即使没有提交,对其他事务也都是可见的。
- 事务可以读取到未提交的数据,称为脏读(dirty read)
- READ COMMITTED(提交读)
- 大多数数据库系统的隔离级别
- 一个事务开始时,只能“看见”已经提交的事务所做的修改
- 即一个事务在开始到提交之前,所做的任何修改对其他事务都是不可见的。
- 称为不可重复读(nonrepeatable read)
- REPEATABLE READ(可重复读)
- 解决脏读问题。保证在同一个事务中多次读取同样记录的结果是一致的。
- 无法解决幻读(Phantom Read)问题。幻读,当某个事务再次读取该范围的记录时,会产生幻行(插入)。InnoDB存储引擎通过多版本并发控制解决幻读问题
- MySQL的默认隔离级别
- SERIALIZEABLE(可串行化)
- 最高的隔离级别。通过强制事务串行化执行,避免幻读问题。
- SERIALIZEABLE会在读取的每一行数据上都加锁,可能导致大量的超时和锁争用的问题。
- 只有在需要确保数据一致性且可以接受没有并发的情况下才考虑使用
死锁
死锁是指两个事务或多个事务在同一个资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。
事务日志
使用事务日志,存储引擎在修改表的数据时只需修改其内存拷贝,再把修改行为记录到硬盘上的事务日志中,而不是每次都将修改的数据本身持久到磁盘。
MySQL中的事务
MySQL支持两种事务型的存储引擎:InnoDB和NDB Cluster
自动提交(AUTOCOMMIT)
- MySQL默认采用自动提交模式,如果不是显式地开始一个事务,则每个查询都被当做一个事务执行提交操作。
- 设置AUTOCOMMIT变量设置西东提交模式
- DDL操作会强制执行COMMIT提交当前的活动事务
- SET TRANSACTION ISOLATION LEVEL设置隔离级别
在事务中混合使用引擎
- 事务是由下层的存储引擎实现的
- 若在事务中混合使用了事务型和非事务型的表,在正常情况提交下不会有问题
隐式和显式锁定
- InnoDB采用两阶段锁定协议
- 隐式锁定,在事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或ROLLBACK的时候才释放,并且所有的锁都是在同一时刻被释放的
- 显式锁定,特定语句实现,在服务器层实现
多版本并发控制
MVCC是行级锁的一个变种,很多情况下避免了加锁操作。大多实现了非阻塞的读操作,写操作也只锁定必要的行
- 通过保存数据在某个时间点的快照来实现的。不管需要执行多次时间,每个事务看到的数据都是一致的。
- 典型的MVCC实现
- 乐观并发控制
- 悲观并发控制
- InnoDB的MVCC,通过在每行记录后面保存两个隐藏列来实现。一个保存行创建时间,一个保存行过期时间(或删除时间)。时间值是系统版本号。每开始一个新的事务,系统版本号都会自动递增。
- MVCC只在REPEATABLE READ和 READ COMMIT两个隔离级别下工作,其他两个隔离级别都和MVCC不兼容。
MySQL的存储引擎
- MySQL会在数据库子目录下创建一个和表同名的.frm文件保存表的定义
InnoDB存储引擎
- 默认的MySQL事务型引擎
- InnoDB可以将每个表的数据和索引放在单独的文件中
- 采用MVCC来支持高并发,并实现四个标准的隔离级别
- 基于聚集索引建立
- 优化,可预测性预读,自适应哈希索引,插入缓冲区
MyISAM存储引擎
- MySQL5.1之前版本,MyISAM是默认的引擎。提高全文索引、压缩、空间函数等,但是不支持事务和行级锁。
存储
- 将表存储在两个文件中,数据文件和索引文件,分别以.MYD和.MYI为扩展名
MyISAM特性
- 加锁和并发,针对整张表加锁。读取时添加共享锁,写入时添加排他锁。
- 修复,可以手动或自动执行检查和修复工作
- 索引特性,支持全文索引
- 延迟更新索引,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或关闭表的时候才会将对应的索引块写入到磁盘。
MyISAM压缩表
- 若表在创建并导入数据以后,不会再进行修改操作,适合压缩
参考文献:《高性能MySQL》