9.MySQL的存储引擎
[toc]
存储引擎简介

- 文件系统- 操作系统组织和存取数据的一种机制。
- 文件系统是一种软件。
 
- 文件系统类型- 不管使用什么文件系统,数据内容不会变化
- 不同的是,存储空间、大小、速度。
 
- Linux的文件系统- CentOS6文件系统:ext4
- CentOS7文件系统:xfs
 
- MySQL引擎- 可以理解为,MySQL的“文件系统”,只不过功能更加强大。
 
- MySQL的存储引擎- MySQL5.5版本之前:MyIsam
- MySQL5.5版本之后:Innodb
 
区别:myisam 表级锁,innodb行级锁
MySQL自带的存储引擎类型
MySQL 提供以下存储引擎
- InnoDB
- MyISAM
- MEMORY
- ARCHIVE
- FEDERATED
- EXAMPLE
- BLACKHOLE
- MERGE
- NDBCLUSTER
- CSV
还可以使用第三方存储引擎
- MySQL当中插件式的存储引擎类型
- MySQL的两个分支
- perconaDB
- mariaDB
| 1 | # 查看当前MySQL支持的存储引擎类型 | 
innodb和myisam物理上的区别
| 1 | # 进入mysql目录 | 
innodb存储引擎的简介
在MySQL5.5版本之后,默认的存储引擎,提供高可靠性和高性能。
**优点: **
- 事务安全(遵从 ACID)
- MVCC(Multi-Versioning Concurrency Control,多版本并发控制)
- InnoDB 行级别锁定
- Oracle 样式一致非锁定读取
- 表数据进行整理来优化基于主键的查询
- 支持外键引用完整性约束
- 大型数据卷上的最大性能
- 将对表的查询与不同存储引擎混合
- 出现故障后快速自动恢复
- 用于在内存中缓存数据和索引的缓冲区池

外键
引用另外一个表中的一列或多列数据,被引用的列应该具有主键约束或者唯一性约束(简单来说外键是另一个表的主键或者唯一约束)。
外键可以不唯一, 可以是空值,用来建立和加强两个表数据之间的连接
| 1 | # 有外键的建表语句 | 
MySQL存储引擎核心特性
- 表空间
- 事务
- 锁
- CSR(自动故障恢复)
- MVCC(多版本并发控制)
- 隔离级别
查看存储引擎
| 1 | # 使用 SELECT 确认当前默认使用的存储引擎 | 
存储引擎的设置
| 1 | # 建表指定存储引擎 | 
Innodb存储引擎核心特性—表空间
表空间介绍

- 共享表空间- 系统数据
- undo
- 临时表
 
- 独立表空间- 用户真实数据
 
表空间位置
| 1 | # 数据目录下(共享表空间) | 
Innodb存储引擎核心特性-事务
什么是事务
主要针对DML语句(update,delete,insert)
一组数据操作执行步骤,这些步骤被视为一个工作单元:
所有步骤都成功或都失败
- 如果所有步骤正常,则执行
- 如果步骤出现错误或不完整,则取消
事务的特性
- A:原子性- 所有语句作为一个单元全部成功执行或全部取消。
 
- C:一致性- 如果数据库在事务开始时处于一致状态,则在执行该。 事务期间将保留一致状态。
 
- I:隔离性- 事务与事务之间是相互隔离的
 
- D:持久性- 事务成功完成后,所做的所有更改都会准确地记录在数据库中。所做的更改不会丢失。
 
事务交易流程

SQL语句类别 DTL
Database Trasation Language(数据事务语言)
语法属性
| 1 | # 开启一个事务 | 
注意:只要执行一条DML开始,就已经开启了一个事务,无需执行begin
DML自动commit
| 1 | # DML语句(默认自动开启commit) | 
事务的生命周期流程

事务的隐式提交
- 即不执行’commit’或’rollback’的情况下自动提交事务- 在事务执行期间,如果执行了DDL或者DCL语句,则自动提交上一个事务
- 在事务执行期间,如果执行了begin或者start transaction会自动提交上一个事务
- 在事务执行期间,如果执行了lock或unlock锁表语句,则会自动提交上一个事务
- 在事务执行期间,如果执行load data infile导出数据,则会提交上一个事务
- 在事务执行期间,如果执行select for update语句,则会提交上一个事务
- 在事务执行期间,如果设置了autocommit=1,则会提交上一个事务
 
Innodb存储引擎核心特性-自动故障恢复(CSR)
redo(重做日志)
- redo:- 顾名思义“重做日志”,是事务日志的一种。
 
- 作用:- 在事务ACID过程中,实现的是“D”持久化的作用。
 

redo log恢复数据过程

当我们执行commit之后,会将数据写入redo log
在一段时间内,redo buffer page中的数据会自动写入redo log
| 1 | 
 | 
undo(回滚日志)
- undo:- 顾名思义“回滚日志”,是事务日志的一种。
 
- 作用:- 在事务ACID过程中,实现的是“A”原子性的作用。当然CI的特性也和undo有关
 
redo+undo(CSR)恢复数据过程
- undo会记录commit的状态 
- 数据执行了commit,data buffer page会写入到磁盘 
- 数据没有执行commit,将数据将会回滚到begin时的状态 

redo和undo的存储位置
| 1 | # redo位置 | 
Innodb存储引擎核心特性-锁
- 锁:- 顾名思义就是锁定的意思。
 
- 作用:- 在事务ACID特性过程中,“锁”和“隔离级别”一起来实现“I”隔离性的作用。
 
锁的力度
- Innodb:- 行级锁(前提:该表中,必须有主键索引)
 
- myisam:- 表级锁
 
锁分类
- 排它锁:- 事务执行期间,阻塞其他事务的修改操作
 
- 共享锁:- 事务执行期间,不阻塞其他事务的查询操作
 
- 乐观锁:- 事务执行期间,谁先提交以谁为准
 
- 悲观锁:- 事务执行期间,其他事务无法查看该数据的变化
 
Innodb存储引擎核心特性-多版本并发控制(MVCC)
多版本并发控制(MVCC)的构成
多版本并发控制是由三个锁构成:
- 排它锁- 只阻塞修改类操作,不阻塞查询类操作
 
- 共享锁- 例如所有用户可以查询同一表的数据
 
- 乐观锁- 乐观锁的机制(谁先提交谁为准)
 
事务的四种隔离级别
- RU:Read Uncommit(未提交读)- 允许事务查看其他事务所进行的未提交更改
 
- RC:Read Commit(提交读)- 允许事务查看其他事务所进行的已提交更改
 
- RR:Repeatable Read(可重复读——InnoDB 的默认级别)**- 确保每个事务的 select 输出一致
 
- SERIALIZABLE(串行化)- 将一个事务的结果与其他事务完全隔离
 
| 1 | # 查看隔离级别(默认为RR级别) | 
企业案例1
项目背景:
公司原有的架构:一个展示型的网站,LAMT,MySQL5.1.77版本(MYISAM),50M数据量。
公司问题:
- 表级锁:对表中任意一行数据修改类操作时,整个表都会锁定,对其他行的操作都不能同时进行。
- 不支持故障自动恢复(CSR):当断电时有可能会出现数据损坏或丢失的问题。
如何解决:
- 提建议将现有的MYISAM引擎替换为Innodb,将版本替换为5.6.38 - 如果使用MYISAM会产生”小问题”,性能安全不能得到保证,使用innodb可以解决这个问题。
- 5.1.77版本对于innodb引擎支持不够完善,5.6.38版本对innodb支持非常完善了。
 
- 实施过程和注意要素准备新环境 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- # 安装MySQL5.6或5.7 
 # mysqldump备份出旧库的所有表
 mysqldump -uroot -p123@qqdianCOM -B world > /tmp/world.sql
 # 替换
 vim /tmp/world.sql
 :%s#ENGINE=MyISAM#ENGINE=InnoDB#g
 # 数据恢复到新环境
 MySQL < /tmp/world.sql
企业案例2
项目背景:
在没有备份数据的情况下,突然断电导致表损坏,打不开数据库。
如何解决:
- 准备新环境 - 1 - mysqld_safe --defaults-file=/data/3307/my.cnf & 
- 拷贝库目录到新库中 - 1 - cp -r /application/mysql/data/world/ /data/3307/data/ 
- 恢复表 - 恢复city表 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33- # 用以前的表结构在新库中建表(找DBA或开发要) 
 show create table world.city;
 ## 删掉外键创建语句
 CREATE TABLE `city` (
 `ID` int(11) NOT NULL AUTO_INCREMENT,
 `Name` char(35) NOT NULL DEFAULT '',
 `CountryCode` char(3) NOT NULL DEFAULT '',
 `District` char(20) NOT NULL DEFAULT '',
 `Population` int(11) NOT NULL DEFAULT '0',
 PRIMARY KEY (`ID`),
 KEY `CountryCode` (`CountryCode`),
 KEY `idx_city` (`Population`,`CountryCode`),
 CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`)
 ) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;
 # 删除表空间文件
 alter table city_new discard tablespace;
 # 拷贝旧表空间文件
 cp -a city.ibd city_new.ibd
 # 授权
 chown -R mysql.mysql *
 # 导入表空间
 alter table city_new import tablespace;
 # 物理删除损坏的表文件
 rm -fr city.frm
 rm -fr city.ibd
 # 改表名
 alter table city_new rename city;
- 恢复country表 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36- # 用以前的表结构在新库中建表(找DBA或开发要) 
 show create table world.country;
 CREATE TABLE `country_new` (
 `Code` char(3) NOT NULL DEFAULT '',
 `Name` char(52) NOT NULL DEFAULT '',
 `Continent` enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL DEFAULT 'Asia',
 `Region` char(26) NOT NULL DEFAULT '',
 `SurfaceArea` float(10,2) NOT NULL DEFAULT '0.00',
 `IndepYear` smallint(6) DEFAULT NULL,
 `Population` int(11) NOT NULL DEFAULT '0',
 `LifeExpectancy` float(3,1) DEFAULT NULL,
 `GNP` float(10,2) DEFAULT NULL,
 `GNPOld` float(10,2) DEFAULT NULL,
 `LocalName` char(45) NOT NULL DEFAULT '',
 `GovernmentForm` char(45) NOT NULL DEFAULT '',
 `HeadOfState` char(60) DEFAULT NULL,
 `Capital` int(11) DEFAULT NULL,
 `Code2` char(2) NOT NULL DEFAULT '',
 PRIMARY KEY (`Code`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 # 删除表空间文件
 alter table country_new discard tablespace;
 # 拷贝旧表空间文件
 cp -a country.ibd country_new.ibd
 # 导入表空间
 alter table country_new import tablespace;
 # 物理删除损坏的表文件
 rm -fr country.frm
 rm -fr country.ibd
 # 改表名
 alter table country_new rename country;
- 恢复countrylanguage表 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26- # 用以前的表结构在新库中建表(找DBA或开发要) 
 show create table world.countrylanguage;
 CREATE TABLE `countrylanguage_new` (
 `CountryCode` char(3) NOT NULL DEFAULT '',
 `Language` char(30) NOT NULL DEFAULT '',
 `IsOfficial` enum('T','F') NOT NULL DEFAULT 'F',
 `Percentage` float(4,1) NOT NULL DEFAULT '0.0',
 PRIMARY KEY (`CountryCode`,`Language`),
 KEY `CountryCode` (`CountryCode`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 # 删除表空间文件.
 alter table countrylanguage_new discard tablespace;
 # 拷贝旧表空间文件
 cp -a countrylanguage.ibd countrylanguage_new.ibd
 # 导入表空间
 alter table countrylanguage_new import tablespace;
 # 物理删除损坏的表文件
 rm -fr countrylanguage.frm
 rm -fr countrylanguage.ibd
 # 改表名
 alter table countrylanguage_new rename countrylanguage;
 
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 奥利奥の麦旋风!




