第七章·DBA-MySQL的存储引擎

存储引擎简介

file

  1. 文件系统
    1. 操作系统组织和存取数据的一种机制。
    2. 文件系统是一种软件
  2. 文件系统类型: ext2、3、4,xfs数据
    1. 不管使用什么文件系统,数据内容不会变化
    2. 不同的是,存储空间、大小、速度
  3. MySQL引擎
    1. 可以理解为,MySQL的"文件系统",只不过功能更强大
  4. MySQL引擎功能
    1. 除了可以提供基本的存取功能,还有更多功能:事务功能、锁定、备份和恢复、优化以及特殊功能

总之,存储引擎的各项特性就是为了保障数据库的安全和性能设计结构。

MySQL自带的存储引擎类型

MySQL 提供以下存储引擎:

01)InnoDB
02)MyISAM
03)MEMORY
04)ARCHIVE
05)FEDERATED
06)EXAMPLE
07)BLACKHOLE
08)MERGE
09)NDBCLUSTER
10)CSV

还可以使用第三方存储引擎:

01)MySQL当中插件式的存储引擎类型
02)MySQL的两个分支
03)perconaDB
04)mariaDB

## 查看所有的存储引擎
mysql[world]> show engines;
+--------------------+---------+
| Engine             | Support |
+--------------------+---------+
| MRG_MYISAM         | YES     |
| CSV                | YES     |
| InnoDB             | DEFAULT |
| BLACKHOLE          | YES     |
| MyISAM             | YES     |
| PERFORMANCE_SCHEMA | YES     |
| ARCHIVE            | YES     |
| MEMORY             | YES     |
| FEDERATED          | NO      |
+--------------------+---------+

## 查看库中哪些表是InnoDB的存储引擎
mysql[world]> select TABLE_SCHEMA,TABLE_NAME,ENGINE from information_schema.tables
where engine='innodb';

## 查看库中哪些表是MyIsam的存储引擎
mysql[world]> select TABLE_SCHEMA,TABLE_NAME,ENGINE from information_schema.tables
where engine='myisam';

innodb和myisam的区别

物理上的区别

#进入mysql目录
[root@db01~l]# cd /application/mysql/data/mysql
#查看所有user的文件
[root@db01 mysql]# ll user.*
# 表结构文件
-rw-rw---- 1 mysql mysql 10684 Mar  6  2017 user.frm
# 数据文件
-rw-rw---- 1 mysql mysql   960 Aug 14 01:15 user.MYD
# 数据文件
-rw-rw---- 1 mysql mysql  2048 Aug 14 01:15 user.MYI

#进入word目录
[root@db01 world]# cd /application/mysql/data/world/
#查看所有city的文件
[root@db01 world]# ll city.*
# 表结构文件
# 数据文件
-rw-rw---- 1 mysql mysql   8710 Aug 14 16:23 city.frm
# 数据文件
-rw-rw---- 1 mysql mysql 688128 Aug 14 16:23 city.ibd

逻辑上区别

innodb存储引擎的简介

在MySQL5.5版本之后,默认的存储引擎,提供高可靠性和高性能。

优点:
01)事务安全(遵从 ACID)
02)MVCC(Multi-Versioning Concurrency Control,多版本并发控制)
03)InnoDB 行级别锁定
04)Oracle 样式一致非锁定读取
05)表数据进行整理来优化基于主键的查询
06)支持外键引用完整性约束
07)大型数据卷上的最大性能
08)将对表的查询与不同存储引擎混合
09)出现故障后快速自动恢复
10)用于在内存中缓存数据和索引的缓冲区池

file
innodb核心特性

重点:

MVCC
事务
行级锁
热备份
Crash Safe Recovery(自动故障恢复)

查看存储引擎

# 查看当前正在使用的存储引擎
mysql[zls]> SELECT @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+

## 查看建表语句
mysql[lw]> show create table student;

mysql[lw]> select TABLE_SCHEMA,TABLE_NAME,ENGINE from information_schema.tables where
engine='innodb' and table_name='stu';

mysql[lw]> show table status like 'stu'\G

设置储存引擎

1.# 编辑MySQL配置文件
[mysqld]
default-storage-engine=<Storage Engine>
default-storage-engine=innodb
default-storage-engine=myisam

2.# 库内临时设置
mysql[(none)]> set global default_storage_engine=myisam;

3.# 建表时指定存储引擎
create table 表名(id int)engine='存储引擎名';

三.真实企业案例

项目背景:

公司原有的架构:一个展示型的网站,LAMT,MySQL5.1.77版本(MYISAM),50M数据量。

小问题不断:

1、表级锁:对表中任意一行数据修改类操作时,整个表都会锁定,对其他行的操作都不能同时进行。

2、不支持故障自动恢复(CSR):当断电时有可能会出现数据损坏或丢失的问题

如何解决:

1、提建议将现有的MYISAM引擎替换为Innodb,将版本替换为5.6.38 1)如果使用MYISAM会产生”小问题”,性能安全不能得到保证,使用innodb可以解决这个问题。
2)5.1.77版本对于innodb引擎支持不够完善,5.6.38版本对innodb支持非常完善了。

2、实施过程和注意要素
​ 1)解决思路与过程

1.开会讨论,停机维护

2.将操作步骤,提前写在文档中
    2.1准备新环境
    新的CentOS系统
    新的MySQL版本
    配置文件优化好
    服务启动好

3.关闭所有连接数据库的服务
systemctl stop php-fpm
systemctl stop tomcat

4.停数据库
systemctl stop mysqld

5.备份数据库中的全部数据
mysqldump -A -R --trigger --single-transaction --master-data=1

6.将备份的数据发送到新环境中
scp rsync

将表的myisam存储引擎改成innodb
mysql[zls]> alter table student engine='myisam';
mysql[zls]> alter table student charset='latin1';
## 方案一:
#!/bin/bash

for table in ` mysql -e 'show tables from zls'|awk 'NR>1'`;do
mysql -e "alter table zls.$table engine='myisam'";
done

## 方案二:
[root@db04 zls]# mysqldump -B zls > /tmp/zls.sql
:%s@ENGINE=MyISAM@ENGINE=InnoDB@g

7.将数据导入到新的数据库中
mysql -uroot -p123 < /tmp/zls.sql

8.将几台web服务器,连接到新库,做测试

9.应用割接

Innodb存储引擎-表空间介绍

表空间:

​ 共享表空间
​ 独立表空间

file

5.5版本以后出现共享表空间概念

表空间的管理模式的出现是为了数据库的储存更容易扩展

5.6版本中默认的是独立表空间

1.共享表空间

查看共享表空间

#物理查看
[root@db01 ~]# ll /application/mysql/data/
-rw-rw---- 1 mysql mysql 79691776 Aug 14 16:23 ibdata1

#命令行查看
mysql> show variables like '%path%';
+----------------------------------+------------------------+
| Variable_name                    | Value                  |
+----------------------------------+------------------------+
| innodb_data_file_path            | ibdata1:12M:autoextend |
+----------------------------------+------------------------+

5.6版本中默认存储:
1.系统数据
2.undo
3.临时表

-rw-rw---- 1 mysql mysql 12582912 Aug 9 10:24 ibdata1 # 共享表空间
-rw-rw---- 1 mysql mysql 50331648 Aug 9 10:24 ib_logfile0 # redo log
-rw-rw---- 1 mysql mysql 50331648 Aug 2 14:45 ib_logfile1 # redo log

5.7版本中默认会将undo和临时表独立出来,5.6版本也可以独立,只不过需要在初始化的时候进行配置

-rw-r----- 1 mysql mysql 79691776 Aug 15 12:02 ibdata1 # 共享表空间
-rw-r----- 1 mysql mysql 50331648 Aug 15 12:02 ib_logfile0 # redo log
-rw-r----- 1 mysql mysql 50331648 Aug 3 17:10 ib_logfile1 # redo log
-rw-r----- 1 mysql mysql 12582912 Aug 15 12:01 ibtmp1 # 临时表

修改共享表空间

共享表空间,初始大小默认:12M:自动扩容
[root@db04 data]# vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
innodb_data_file_path=ibdata1:76M;ibdata2:50M:autoextend
[root@db04 data]# systemctl restart mysqld
[root@db04 data]# du -sh ibdata2
-rw-r----- 1 mysql mysql 79691776 Aug 16 09:48 ibdata1
-rw-r----- 1 mysql mysql 52428800 Aug 16 09:48 ibdata2

2.独立表空间

对于用户自主创建的表,会采用此种模式,每个表由一个独立的表空间进行管理

1.查看独立表空间

#物理查看
[root@db01 ~]# ll /application/mysql/data/world/
-rw-r----- 1 mysql mysql 8710 Aug 13 12:00 city.frm # 表结构
-rw-r----- 1 mysql mysql 786432 Aug 13 12:00 city.ibd # 独立表空间

#命令行查看
mysql> show variables like '%per_table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+

真实企业案例

在没有备份数据的情况下,突然断电导致表损坏,打不开数据库。

1.准备新环境,安装完数据库启动

2.将data目录备份出来导入新环境

[root@db01 ~]# cp -r /application/mysql/data/world/ /data/3307/data/

3.启动新数据库

[root@db01 ~]# mysqld_safe --defaults-file=/data/3307/my.cnf &

4.要知道建表语句,找开发要

mysql> 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;

5.删除新表的表空间文件

alter table world.country_new discard tablespace;

6.将旧表的表空间,拷贝成新表的表空间

[root@db02 world]# cp -a country.ibd country_new.ibd

# 光物理拷贝表空间会报错,country_new的表空间已经被删除
mysql> select * from country_new;
ERROR 1814 (HY000): Tablespace has been discarded for table 'country_new'

7.将新表的表空间,导入进去

mysql> alter table world.country_new import tablespace;

8.此时旧表还存在,数据依旧会写入旧表

# 两种解决方案:
- 跟开发说,去改代码,把所有要增删改成country表的代码改成country_new
- 删除已损坏的表,将新表改名为旧表名
[root@db02 world]# rm -f country.ibd
[root@db02 world]# rm -f country.frm
mysql> alter table country_new rename country;

8.旧业务先停机
9.使用binlog截取新数据,恢复到新环境中
10.业务应用割接到新环境

Innodb核心特性-事务

1.什么是事务

主要针对DML语句(update, delete, insert)

一组数据操作执行步骤,这些步骤被视为一个工作单元:
1)用于对多个语句进行分组
2)可以在多个客户机并发访问同一个表中的数据时使用

所有步骤都成功或都失败
1)如果所有步骤正常,则执行
2)如果步骤出现错误或不完整,则取消

2.事务的通俗理解

伴随着"交易"出现的数据库概念

我们理解的“交易”是什么?
1)物与物的交换(古代)
2)货币现金与实物的交换(现代1)
3)虚拟货币与实物的交换(现代2)
4)虚拟货币与虚拟实物交换(现代3)

数据库中的"交易"是什么

1)事务又是如何保证“交易”的“和谐”?
2)ACID

3.事务ACID特性

Atomic(原子性)
所有语句作为一个单元全部成功执行或全部取消。

Consistent(一致性)
如果数据库在事务开始时处于一致状态,则在执行该。事务期间将保留一致状态。

Isolated(隔离性)
事务之间不相互影响。

Durable(持久性)
事务成功完成后,所做的所有更改都会准确地记录在
数据库中。所做的更改不会丢失。

4.事务流程举例

file

5.事务的控制语句

start transaction(或 begin):显式开始一个新事务
savepoint:分配事务过程中的一个位置,以供将来引用
commit:永久记录当前事务所做的更改
rollback:取消当前事务所做的更改
rollback to savepoint:取消在 savepoint 之后执行的更改
release savepoint:删除 savepoint 标识符
set autocommit:为当前连接禁用或启用默认提交模式

## 开启事务语句
begin;
start transaction;

情况一:只要执行了DML语句,就会开启一个事务
insert update delete(这种情况因为是默认自动提交)

情况二:begin执行后,会开启一个事务

1.事务的生命周期

# 一个成功的事务生命周期
begin;
sql1
sql2
sql3
...
commit;

# 示例:
mysql> create table stu(id int,name varchar(10),sex enum('f','m'),money int);
mysql> begin;
mysql> insert into stu(id,name,sex,money) values(1,'zhang3','m',100), (2,'zhang4','m',110);
mysql> commit;

# 一个失败的事务生命周期
begin 开启一个事务
DML
DML
DML
DML
...
rollback;

# 示例 事务回滚
mysql> begin;
mysql> update stu set name='zhang3';
mysql> delete from stu;
mysql> rollback;

2.自动提交

#查看自动提交
mysql> show variables like 'autocommit';
#临时关闭
mysql> set autocommit=0;
#永久关闭
[root@db01 world]# vim /etc/my.cnf
[mysqld]
autocommit=0

3.事务隐式提交情况

在事务运行期间,手工执行begin的时候会自动提交上个事务
在事务运行期间,加入DDL、DCL操作会自动提交上个事务
在事务运行期间,执行锁定语句(lock tables、unlock tables)
load data infile
select for update
在autocommit=1的时候

事务的日志(CSR自动故障恢复)

Redo是什么?

redo,顾名思义"重做日志",是事务日志的一种

作用是什么?

在事务ACID过程中,实现的是“D”持久化的作用。

file

特性:WAL(Write Ahead Log)日志优先写
REDO:记录的是,内存数据页的变化过程

REDO工作过程

#执行步骤
update t1 set num=2 where num=1; 

1)首先将t1表中num=1的行所在数据页加载到内存中buffer page
2)MySQL实例在内存中将num=1的数据页改成num=2
3)num=1变成num=2的变化过程会记录到,redo内存区域,也就是redo buffer page中

#提交事务执行步骤
commit; 

1)当敲下commit命令的瞬间,MySQL会将redo buffer page写入磁盘区域redo log
2)当写入成功之后,commit返回ok

file

redo数据实例恢复过程

file

事务日志undo

undo是什么?

undo,顾名思义“回滚日志”,是事务日志的一种。

作用是什么?

在事务ACID过程中,实现的是“A”原子性的作用。当然CI的特性也和undo有关

file

file

故障可能遇到的三种情况:

1.提交了,commit,数据保存到磁盘上redo log中了,断电了数据还没有写入独立表空间
2.没提交,数据也保存到磁盘上redo log中了,断电了,数据还没有写入独立表空间
3.没有提交,数据也没有保存到 redo log中,断电了,数据还没写入独立表空间

file

事务中的锁

1)什么是“锁”?

“锁”顾名思义就是锁定的意思。

2)“锁”的作用是什么?

在事务ACID特性过程中,“锁”和“隔离级别”一起来实现“I”隔离性的作用。

file

排它锁:在事务操作期间,实现行级锁,保证数据的一致性
共享锁:在事务操作期间,其它事务不可以修改数据,但是可以查询数据
乐观锁:谁先提交以谁
悲观锁:只要事务执行期间,其它事务均无法查询

多版本并发控制(MVCC)

1)只阻塞修改类操作,不阻塞查询类操作
2)乐观锁的机制(谁先提交谁为准

锁的粒度

MyIsam:低并发锁(表级锁)
Innodb:高并发锁(行级锁)

事务的隔离级别

read uncommitted (RU级别:未提交读)
允许事务查看其他事务所进行的未提交更改

read committed (RC级别,已提交读)
允许事务查看其他事务所进行的已提交更改

repeatable read (RR级别)
确保每个事务的 SELECT 输出一致
InnoDB 的默认级别

serializable (串行化级别)
将一个事务的结果与其他事务完全隔离

#查看隔离级别
mysql> show variables like '%iso%';
#修改隔离级别为RU
[mysqld]
transaction_isolation=read-uncommit
mysql> use oldboy
mysql> select * from stu;
mysql> insert into stu(id,name,sex,money) values(2,'li4','f',123);
#修改隔离级别为RC
[mysqld]
transaction_isolation=read-commit

山林不向四季起誓 荣枯随缘