用了多年的SQL Server 后, 最近开始转用Mysql 作为主要的数据库. 此系列文章记录了此间学到了知识和经验.
作为开篇, 首先介绍的是MySql 的一些基础知识.
1. MySql 逻辑架构
MySq 存储引擎最与众不同的特性是它的存储引擎架构. 这种架构将查询处理(Query Processing) 以及其它系统任务(Server Task)和数据的存储/提取 进行了分离.
这样存储和处理相分离的设计, 可以在使用时根据性能,特性,以及其它需求来选择数据存储的方式.
例如, 可以主表使用InnoDB, 而用MyISAM作为缓存表的引擎, 将会得到更小的索引暂用空间, 并且可以做全文搜索.
从逻辑上, MySql 架构分为三层: 连接/线程处理层; 核心服务层; 存储引擎.
1.1 连接/线程处理层
类似大多数基于网络的C/S 工具或服务. 盖层主要负责连接处理, 授权认证, 安全等等.
每个客户端连接在服务器进程中拥有一个线程. 服务器会负责缓存线程, 从而不需要频繁新建销毁.
1.2 核心服务层
包含查询解析, 分析, 优化, 缓存以及所有的内置函数.
该层同时实现了所有跨存储引起的功能: 存储过程, 触发器, 视图等.
1.3 存储引擎
负责数据的存储和提取.
除了InnoDB会解析外键定义(因为MySql 服务器本身没有实现) 外, 存储引起不会去解析SQL.
核心服务层通过存储引擎API与存储引擎通信. 该API使得不同存储引擎的差异对上层的查询过程透明.
不同的存储引擎间, 不会互通信, 而只是简单地响应上层服务器的请求.
2 并发控制时的锁
锁粒度的选择, 是在锁的开销和数据的安全性之间寻求平衡.
多数数据库会在表上施加row-level 锁, 并采用手段保证锁较多时的性能.
MySql 每种存储引擎都可以实现自己的锁策略和锁粒度.
3 MySql 中的事务
MySql 提供了两种事务型的存储引擎: InnoDB和NDB Cluster.
MySql 默认采用自动提交(AutoCommit)模式. 若不是显式地开始一个事务,则每个查询都被当做一个事务执行提交操作.
对于MyISAM或内存表, 没有Commit 或Rollback 的概念. 相当于一直处于AutoCommit 模式.
有一些命令, 在执行之前会强制执行Commit 提交当前的活动事务. 典型的例子, 在DDL中, 如果是会导致大量数据改变的操作, 如Alter Table, Lock Tables.
MySql 服务层不管理事务, 事务由下层的存储引擎实现. 如果在同一事务中,使用多种存储引擎是不可靠的.
3.1 隐式和显式锁定
InnoDB采用的是两阶段锁定协议. 在事务执行过程中, 随时都可以执行锁定. 锁只有在执行Commit 或者RollBack 时才会在同一时刻释放.
InnoDB 会根据隔离级别在需要时自动加锁.
另外,也支持 Lock tables 和UnLock Tables语句来进行显式加锁.
并且, MySql 在服务层也实现了Lock tables 和UnLock Tables的支持. 但并不能替代事务处理. 如需用到事务, 还是应该选择事务型存储引擎.
3.2 事务日志
存储引擎在修改表数据时, 只需修改其内存拷贝, 再把该修改行为记录到持久在硬盘上的事务日志中, 而不用每次都将修改数据本身持久到硬盘.
采用追加的方式. 写日志是磁盘上一小块区域内的顺序I/O, 速度更快.
日志持久化后, 内存中修改的数据, 在后天慢慢地刷回硬盘.
事务日志也被成为预写式日志(Write-Ahead Logging). 修改数据需要两次写磁盘.
若在数据还未写回磁盘时崩溃, 会在重启后自动修复该部分修改的数据.
3.3 多版本并发控制(MVCC)
通过保存数据在某个时间点的快照来实现.
在每行记录上保存两个隐藏的列, 行的创建时间和过期(删除)时间. 时间值是系统版本号.
每开始一个事务, 系统版本号递增.
事务开始时刻的系统版本号作为事务的版本号, 用来和查询到的每行记录的版本号进行比较.
使多数读操作不需要加锁. 但需要额外的空间和检查工作.
对隔离级别的支持.
只支持Repeatable Read和Read Committed隔离级别.
Read unCommitted 总读取最新的数据, 而不是当前事务版本的数据行.
Serialisable 会对所有读取的行都加锁.
4 MySql 存储引擎
4.1 存储
MySql 使用文件系统的目录和文件保存数据库(Schema)和表的定义.
库是数据目录的子目录.
表会有同名.frm文件保存表的定义.
所以, 大小写敏感性和具体的平台密切相关.
4.2 InnoDB
数据存储在表空间(tablespace)中, 表空间是由InnoDB管理的黑盒子, 由一系列的文件组成.
采用MVCC 来支持高并发. 并且实现了四个标准的隔离级别.
表基于聚族索引建立的. 对铸件查询有很高的性能, 但是二级索引中必须包含主键列. 所以主键列应尽可能的小.
适合场景: 处理大量的短期事务(多数情况下正常提交,很少被回滚), 支持自动崩溃恢复.
4.3 MyISAM
提供了全文检索,压缩,空间函数等特性.
不支持事务和行级锁. 且无法做到崩溃后恢复.
加锁与并发. 读取时对表加共享锁, 写入时对表加排它锁.
适合场景: 对于只读数据, 或者表比较小, 能够忍受修复操作.
引擎选择的因素: 事务, 备份, 崩溃恢复, 特有的特性.