MySQL 学习(7)—— 存储引擎 | 8月更文挑战

515 阅读16分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

1. 简介

相当于 Linux 文件系统,只不过比文件系统强大

2. 功能了解

  • 数据读写
  • 数据安全与一致性
  • 提高性能
  • 热备份
  • 自动故障恢复
  • 高可用方面支持等

3. 存储引擎介绍

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.01 sec)

默认的存储引擎是:InnoDB

下一代存储引擎:RocksDB、MyRocks、TokuDB 原因:压缩比较高,数据的插入性能高,其他功能和 InnoDB 没差。

4. InnoDB 核心特性说明

  1. 事务(Transaction)
  2. MVCC(Multi-Version Cocurrency Control,多版本并发控制)
  3. 外键
  4. ACSR(Auto Crash Safey Recovery)自动的故障安全恢复
  5. 行级锁(Row-level Lock)
  6. 支持热备份(Hot Backup)
  7. 复制(多线程,GTID,MTS)

5. 存储引擎的查看

5.1 查看存储引擎设置

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
mysql> select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set (0.02 sec)

5.2 查看表存储引擎状态

mysql> show create table student;
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                              |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| student | CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号',
  `sname` varchar(64) NOT NULL COMMENT '姓名',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` char(4) NOT NULL COMMENT '性别',
  `intime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入学时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`sname`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4             |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

6. 存储引擎的修改

6.1 修改存储引擎

mysql> alter table student engine=innodb;
Query OK, 4 rows affected (0.06 sec)
Records: 4  Duplicates: 0  Warnings: 0

6.2 整理碎片

mysql> alter table student engine=innodb;
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

注意:只有 InnoDB 可以

可以用来定期碎片整理。

7. InnoDB 存储引擎物理存储结构

7.1 最直观的存储方式(/data/mysql/data)

  • ibdata1:系统数据字典信息(统计信息),undo 表空间等数据(5.6版本,共享表空间保留,只用来存储:数据字典信息,undo,临时表;5.7 版本,临时表被独立出来了;8.0 版本,undo 也被独立出去了)
  • ib_logfile0、ib_logfile1:redo 日志文件,事务日志文件
  • ibtmp1:临时表空间磁盘位置,存储临时表
  • frm:存储表的列信息
  • ibd:表的数据行和索引

7.2 表空间(Tablespace)

7.2.1 表空间数据问题

  • ibdata1:整个库的统计信息 + undo
  • ibd:数据行和索引

5.5 共享表空间 =》 5.6 独立表空间

7.2.2 共享表空间(ibdata1 ~ N)

5.5 版本默认模式,5.6 中转换为了独立表空间 需要将所有数据存储到同一个表空间中,管理比较混乱

是 5.5 版本出现的管理模式,也是默认的管理模式 5.6 版本共享表空间被保留,只是用来存储:数据字典信息、undo、临时表 5.7 版本 临时表被独立出来了 8.0 版本,undo 也被独立出来了

具体变化参考官方文档:

dev.mysql.com/doc/refman/… dev.mysql.com/doc/refman/… dev.mysql.com/doc/refman/…

共享表空间设置(在搭建 MySQL 时,初始化数据之前设置到参数文件中)

查看共享表空间设置:

mysql> select @@innodb_data_file_path;
+-------------------------+
| @@innodb_data_file_path |
+-------------------------+
| ibdata1:12M:autoextend  |
+-------------------------+
1 row in set (0.00 sec)
mysql> show variables like '%extend%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| innodb_autoextend_increment | 64    |
+-----------------------------+-------+
1 row in set (0.00 sec)

该配置文件的含义是:

  • 共享表空间的名称是 ibdata1;
  • 分配的空间大小是 12M;
  • 如果空间大小不够的话,autoextend,自动扩容;
  • 每次扩容的大小是 64M

我们可以在初始化配置文件时,就制定共享表空间大小

mysqld --initialize-insecure xxxxxxxxx innodb_data_file_path=ibdata1:512M:ibdata2:512M:autoextend innodb_autoextend_increment=64

指定两个配置文件 ibdata1,ibdata2,每个大小 512M,用完 ibdata1 则用 ibdata2,两个都用完了,再自动扩容。

7.2.3 独立表空间

从 5.6 开始,默认表空间不再使用共享表空间,替换为独立表空间

主要存储的是用户数据。

存储特点为:一个表为一个 ibd 文件,存储数据行和索引信息

结论:一个数据表=ibd+frm+ibdata1

Redo Log:ib_logfile0、ib_logfile1,重做日志 Undo Log:ibdata1、ibdata2(存储在共享表空间中),存储回滚日志 临时表:ibtmp1,在做 join、union 操作时产生临时数据,用完自动清除

mysql> select @@innodb_file_per_table;
+-------------------------+
| @@innodb_file_per_table |
+-------------------------+
|                       1 |
+-------------------------+
1 row in set (0.00 sec)

1 表示开启了独立表空间。

表空间模式的切换只会影响后续的表,之前的表不会受到影响。

7.2.4 独立表空间迁移

直接迁移 .rfm 文件和 .ibd 文件是不可以的,因为表的元数据信息还在 ibdata1 文件中,缺少这个信息,就没办法看这个表了。因此,我们需要一个一模一样的元数据,那么怎么样才能有一模一样的元数据呢,我们把最开始的建表语句拿过来就可以了。

首先,我们在 3306 库上有个 student 表,我想给他迁移到多实例 3307 库下。

我们把文件复制过去:

# cp /data/mysql/data/account/student.* /data/3307/data/account/
# cd /data/3307/data/account/
# chown mysql.mysql student.*

我们再去 3307 库上查看这个表:

Database changed
mysql> show tables;
+-------------------+
| Tables_in_account |
+-------------------+
| student           |
+-------------------+
1 row in set (0.00 sec)

发现是可以查看到的。那么我们再用 desc 命令执行一下。

mysql> desc student;
ERROR 1146 (42S02): Table 'account.student' doesn't exist

发现这个命令是不可以执行的,为什么呢,是因为 desc 命令查看这个表的元数据信息了,虽然我们有 .frm 文件,但是数据字典和 .frm 文件不一样,.frm 文件只是这个表的结构信息,但是 desc 命令是使用系统的配置文件。

虽然我们能看到这个表名,但是看不了列信息,也看不了数据信息。

那缺什么呢,其实是缺少 iddata1 里面的统计信息。

元数据怎么来的呢?元数据不能直接进行增删改查,只能通过专用的命令来生成,只能通过专用的命令来查。

那我们怎么生成呢?我们只能把它创建出来了。我们找到最开始的建表语句。

我们先把这两个文件删了

# mv /data/3307/data/account/student.* /tmp/

我们去查看一下建表语句

mysql> show create table student;
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                              |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| student | CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号',
  `sname` varchar(64) NOT NULL COMMENT '姓名',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` char(4) NOT NULL COMMENT '性别',
  `intime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入学时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`sname`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4             |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

我们再去 3307 库中创建一下:

mysql> CREATE TABLE `student` (
    ->   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号',
    ->   `sname` varchar(64) NOT NULL COMMENT '姓名',
    ->   `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
    ->   `sex` char(4) NOT NULL COMMENT '性别',
    ->   `intime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入学时间',
    ->   PRIMARY KEY (`id`),
    ->   KEY `idx_name` (`sname`)
    -> ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
ERROR 1146 (42S02): Table 'account.student' doesn't exist

好像不可以,我们把数据库删一下:

mysql> drop database account;
Query OK, 0 rows affected (0.01 sec)
mysql> create database account;
Query OK, 1 row affected (0.00 sec)

mysql> use account;
Database changed
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号',
  `sname` varchar(64) NOT NULL COMMENT '姓名',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` char(4) NOT NULL COMMENT '性别',
  `intime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入学时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`sname`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

ERROR 1146 (42S02): Table 'account.student' doesn't exist

再创建还是不可以。

我们试着修改一下名字:

CREATE TABLE `student1` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号',
  `sname` varchar(64) NOT NULL COMMENT '姓名',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` char(4) NOT NULL COMMENT '性别',
  `intime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入学时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`sname`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.09 sec)

结果创建成功了。

我们将 .ibd 文件再复制过去,.rfm 文件就不需要了,因为已经有了。

之前的数据库表文件:

-rw-r----- 1 mysql mysql     60 1月  23 22:36 db.opt
-rw-r----- 1 mysql mysql   8714 1月  27 21:46 student.frm
-rw-r----- 1 mysql mysql 114688 1月  27 21:46 student.ibd

新创建的数据库表文件:

-rw-r----- 1 mysql mysql     65 1月  28 13:45 db.opt
-rw-r----- 1 mysql mysql   8714 1月  28 13:46 student1.frm
-rw-r----- 1 mysql mysql 114688 1月  28 13:46 student1.ibd

我们把 .ibd 文件复制过去

# cp /data/mysql/data/account/student.ibd /data/3307/data/account/
# chown mysql.mysql /data/3307/data/account/student.ibd

原来有一个 student1.ibd 文件,但是我们不能直接覆盖,也不能直接 rm,那么我么怎么处理呢,我们得需要使用数据库命令:

mysql> alter table student1 discard tablespace;
Query OK, 0 rows affected (0.09 sec)

然后,我们查看一下文件,发现 student1.ibd 文件没有了。

-rw-r----- 1 mysql mysql     65 1月  28 13:45 db.opt
-rw-r----- 1 mysql mysql   8714 1月  28 13:46 student1.frm
-rw-r----- 1 mysql mysql 114688 1月  28 13:50 student.ibd

我们再把 student.ibd 文件给复制过去

# mv student.ibd student1.ibd

那么我们现在可以查看数据了吗?我们试一下

mysql> select * from student1;
ERROR 1814 (HY000): Tablespace has been discarded for table 'student1'

我们得再加上 tablespace,把 .ibd 文件导入进去

mysql> alter table student1 import tablespace;
Query OK, 0 rows affected, 1 warning (0.07 sec)

我们再来查看一下:

mysql> select * from student1;
+----+--------+-----+-----+---------------------+
| id | sname  | age | sex | intime              |
+----+--------+-----+-----+---------------------+
|  1 | 关羽   |  20 | m   | 2021-01-24 20:21:50 |
|  2 | 刘备   |  21 | m   | 2021-01-24 20:23:23 |
|  3 | 赵云   |  22 | m   | 2021-01-24 20:24:38 |
|  4 | 黄忠   |  23 | m   | 2021-01-24 20:24:38 |
+----+--------+-----+-----+---------------------+
4 rows in set (0.00 sec)

总结

  1. 创建和原表结构一致的空表
  2. 将空表的 ibd 文件删除:alter table table_name discard tablespace;
  3. 将原表的 ibd 拷贝过来,并且修改权限;
  4. 将原表 ibd 进行导入:alter table table_name import tablespaces;

作用:可以用于数据备份、复制等。

8. InnoDB 核心特性

8.1 事务

8.1.1 事务的 ACID 特性

  • Atomic(原子性)

    • 所有语句作为一个单元全部成功执行或全部取消,不能出现中间状态。
  • Consistent(一致性)

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

    • 事务之间不相互影响。
  • Durable(持久性)

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

8.1.2 事务的生命周期(标准的事务控制语句)

  1. 如何开启事务

    • begin;
  2. 标准的事务语句

    • DML
      • insert
      • update
      • delete
  3. 事务的结束

    • 提交:commit;
    • 回滚:rollback;(注意回滚只能回滚未提交的)

8.1.3 自动提交机制(autocommit)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)

只要执行了 DML 语句,MySQL 就会自动开始 begin,自动提交。

在线修改参数:

  1. set autocommit=0; 会话级别修改,只影响当前会话,即时生效
mysql> set autocommit=0;
Query OK, 0 rows affected (0.01 sec)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)

我们在另一个会话,查看一下:

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)

我们把会话断开再重连查看一下:

mysql> exit
Bye
[root@VM-0-3-centos account]# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 146
Server version: 5.7.26 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)
  1. set global autocommit=0; 全局级别修改,断开窗口重连后生效。影响所有新开的窗口
mysql> set global autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)

我们去另一个还没断开的窗口查看一下:

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)

我们把窗口断开再重连一下,再查看一下:

mysql> exit
Bye
[root@VM-0-3-centos ~]# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 143
Server version: 5.7.26 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)
  1. 修改配置文件,永久生效。需要重启
vim /etc/my.cnf
autocommit=0

8.1.4 隐式提交的情况

触发隐式提交的语句:

begin
a
b
(commit) 隐式提交
begin / set 命令

其他导致提交的非事务语句:

  • DDL 语句:alter、create、drop
  • DCL 语句:grant、revoke、set password
  • 锁定语句:lock tables、unlock tables

导致隐式提交的语句示例:

  • truncate table
  • load data infile
  • select for update

8.2 事务的 ACID 如何保证》

8.2.1 一些概念名词

  • redo log:

    • 重做日志,ib_logfile0~1,50M 大小,轮询使用
  • redo log buffer:

    • redo 内存区域
  • ibd:

    • 存储数据行和索引
  • buffer pool:

    • data buffer pool,缓冲区池,数据和索引的缓冲
  • LSN:

    • 日志序列号。
    • 存储在磁盘数据页、redo 文件、buffer pool、redo buffer。
    • MySQL 每次数据库启动,都会比较磁盘数据页和 redolog 的 LSN,必须要求两者 LSN 一致数据库才能正常启动
  • WAL:

    • write ahead log。日志优先写的方式实现持久化
    • 日志是优先于数据写入磁盘的
  • 脏页:

    • 内存脏页,内存中发生了修改,没写入到磁盘之前,我们把内存页称之为脏页。
  • CKPT:

    • checkpoint,检查点,就是将脏页刷写到磁盘的动作
  • TXID:

    • 事务号,InnoDB 会为每一个事务生成一个事务号,伴随着整个事务

8.2.2 事务日志 —— redo

作用:

  • 主要功能:保证 “D”,AC 也有一定的作用

记录了什么?

  • 记录了内存数据页的变化。
  • 提供快速的持久化功能(WAL)
  • CSR 过程中实现前滚的操作(磁盘数据页和 redo 日志 LSN 一直)

03259f595da74972b4f56d0599cff81e.png

redo 日志位置

redo 的日志文件:ib_logfile0、ib_logfile1

redo buffer

redo 的 buffer:数据页的变化信息 + 数据页当时的 LSN 号

redo 的刷写策略

commit; 刷新当前事务的 redo buffer 到磁盘 还会顺便将一部分 redo buffer 中没有提交的事务日志也刷新到磁盘

MySQL:在启动时,必须抱枕 redo 日志文件和数据文件 LSN 必须一致,如果不一致就会触发 CSR,最终保证一致。

MySQL CSR —— 前滚

MySQL:在启动时,必须保证 redo 日志文件和数据文件 LSN 必须一致,如果不一致就会触发 CSR,最终保证一致

情况一:

我们做了一个事务:begin; update; commit.

  1. 在 begin ,会立即分配一个 TXID=tx_01.
  2. update 时,会将需要修改的数据页(dp_01,LSN=101),加载到 data buffer 中
  3. DBWR 线程,会进行 dp_01 数据页修改更新,并更新 LSN=102
  4. LOGBWR 日志写线程,会将 dp_01 数据页的变化 +LSN+TXID 存储到 redobuffer
  5. 执行 commit 时,LGWR 日志写线程会将 redobuffer 信息写入 redolog 日志文件中,基于 WAL 原则,在日志完全写入磁盘后,commit 命令才执行成功,(会将此日志打上 commit 标记)
  6. 假如此时宕机,内存脏页没有来得及写入磁盘,内存数据全部丢失
  7. MySQL 再次重启时,必须要 redolog 和磁盘数据页的 LSN 是一致的。但是,此时 dp_01,TXID=tx_01 磁盘是 LSN=101,dp_01,TXID=tx_01,redolog 中 LSN=102 MySQL 此时无法正常启动,MySQL 触发 CSR,在内存追平 LSN 号,触发 ckpt,将内存数据页更新到磁盘,从而保证磁盘数据页和 redolog LSN 一致。这时 MySQL 正常启动。

以上的工作过程,我们把它称之为基于 REDO 的"前滚操作"

8.2.3 undo —— 回滚日志

作用

在 ACID 特性中,主要保证 A 的特性,同时对 CI 也有一定功效

记录了什么

  1. 记录了数据修改之前的状态;
  2. rollback 时将内存的数据修改恢复到修改之前
  3. 在 CSR 中实现未提交数据的回滚操作
  4. 实现一致性快照,配合锁机制,保证 MVCC,读和写的操作不会互相阻塞

8.2.4 锁

实现了事务之间的隔离功能。

InnoDB 中实现的行锁(row-level lock)

gap

next-lock

8.2.5 隔离级别

  • RU:读未提交,可脏读
  • RC:读已提交,可能出现幻读,可以防止脏读
  • RR:可重复度,功能是防止“幻读”现象,利用的是 undo 的快照技术 + GAP(间隙锁)+ NextLock(下键锁)
  • SR:可串行化,可以防止死锁,但是并发事务性能较差

MVCC ------> undo 快照

  • RU 会出现脏读
  • RC 会出现不可重复读
  • RR 通过 MVCC 基础解决了不可重复读,但是有可能会出现幻读现象,可以通过 GAP + NextLock 进行避免。

MySQL 查看当前隔离级别:

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

在 RR 模式下,通过 GAP 和 Next-lock 避免幻读现象,必须索引支持。

8.2.6 InnoDB 核心参数

  • 存储引擎默认设置:
default_storage_engine=innodb
  • 表空间模式:
innodb_file_per_table=1
  • 共享表空间文件个数和大小
innodb_data_file_path=ibdata1:512M:ibdata2:512M:autoextend
  • "双一"表中的其中一个
innodb_flush_log_at_trx_commit=1
  • 日志刷新方法
innodb_flush_method=(O_DERECT, fsync)

默认是 fsync,建议是 O_DERECT

fsync 模式:

a3f4a73951d537abd12c432a00c19949.png

O_DIRECT 模式:

78cbe62cabc43e79b1577de84b4c18a0.png

O_DSYNC

fc318225a39f20369199d720bbf4375a.png

最高安全模式

innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DERECT

最高性能模式

innodb_flush_log_at_trx_commit=0
innodb_flush_method=fsync
  • redo 日志大小
innodb_log_buffer_size=16777216
innodb_log_file_size=50331648
innodb_log_file_in_group=3
  • 脏页刷写策略
innodb_max_dirty_pages_pct=75

还有哪些机制会触发写磁盘?

  • CSR
  • redo 空间满了的时候