存储引擎

简介

相当于linux文件系统,只不过比文件系统更加强大
MySQL支持同一个实例,存在多种存储引擎(于 DB2,sqlserver,oracle都不一样),是针对表级别设计的

功能了解

  • 数据读写
  • 数据安全性和一致性
  • 提高性能(提供了缓存区和索引)
  • 热备份
  • 自动故障恢复
  • 高可用方面的支持

存储引擎介绍

MySQL的大致引擎分类

InnoDB(默认)
MyISAM
MEMORY
CSV
第三方存储引擎: ROCKSDB, myROCKS,TokuDB,属于压缩比高,数据插入性能高,其他功能和InnoDB一样。不过MySQL需要插件支持

同源产品存储引擎

perconaDB XtraDB(默认)
MariaDB InnoDB(默认)

InnoDB存储引擎的核心特性说明

  • 事务
  • 行锁(MyISAM表级锁)
  • MVCC(多版本并发控制)
  • 外键
  • ASCR(自动故障恢复)
  • 热备(MyISAM温备)
  • 复制(多线程,GTID,MTS)

存储引擎查看

  • show engines 查看M有SQL自带的存储引擎
  • SELECT @@default_storage_engine 查看当前MySQL的存储引擎

查看表的存储引擎

show create table 表名

存储引擎修改

alter table 表名 engine='innodb'

存储引擎整理碎片

碎片: 是在做delete时,逐行删除原有数据时,原有数据的空间不会立即释放掉,所以会产生碎片。碎片中的数据越来越多,数据页就会出现间隙,所以索引也会出现间隙。影响查询效率.
alter table city engine='innodb'整理碎片(前提表是innodb引擎),会有短暂的锁表
另一种方法:先把表数据导出来,truncate原先的表,再表导入进去(最干净,没有碎片)

批量替换zabbix小表innodb为tokudb

select concat('alter table',table_schema,'.',table_name,'engine=tokudb') from information_schema.tables where table_schema='zabbix'

InnoDB 存储的物理结构(最直观的存储方式/data/mysql/data)

  • ibdata1: 共享表空间
    MySQL5.6: 存放数据字典,undo日志,临时表中的数据
    MySQL5.7: 存放数据字典,undo日志
    MySQL8.0:存放数据字典
  • ib_logfile0~ib_logfile1: 存放redo日志,事务日志文件
  • ibtmp1: 临时表空间设置,存放临时表
  • frm: 存储表的列信息
  • ibd: 存放表的数据和索引

表空间(tablespace)

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

共享表空间(ibdata1~ibdataN)

MySQL5.5: 默认共享表空间模式,所有的数据都存在共享表空间里
MySQL5.6: 转换为独立表空间,共享表空间只用来存储数据字典,undo日志,临时表
MySQL5.7: 临时表被独立出去
MySQL8.0: undo日志也被独立出去
查看共享表空间

mysql> select @@innodb_data_file_path;
+-------------------------+
| @@innodb_data_file_path |
+-------------------------+
| ibdata1:12M:autoextend  |
+-------------------------+
表示初始值一个共享表空间,初始大小12M,自动增长,每次增长64M
共享表空间,可以在MySQL初始化时指定,如指定两个共享表空间文件,先把ibdata1用完,在用ibdata2

独立表空间(ibd)

从5.6开始,默认表空间不再使用共享表空间,替换为独立表空间。
存储特点:一个表一个ibd文件,存储数据行+ 索引信息
基本表结构元数据存储: xx.frm

最终结论

一张innodb表=ibd+ibdata1+frm

MySQL存储日志

  • redo log: ib_logfile0 ib_logfile1,重做日志
  • undo log: ibdata1 ibdata2(存储共享表空间中),回滚日志
  • 临时表: ibtmp1 ,在做join union操作产生的临时数据,用完自动清理(当分配的MySQL内存不够时)

独立表空间设置问题

+-------------------------+
| @@innodb_file_per_table |
+-------------------------+
|                       1 |
+-------------------------+
默认为1,表示1个表,代表一个独立的表空间文件

独立表空间迁移

alter table t100 discard tablespace;   //清楚t100表空间数据
alter table t100 import tablespace;    //导入t100 ibd数据

独立表空间迁移步骤

1 .建立和原表结构一致的表
2 .将空表的idb文件删除alter table t100 discard tablespace
3 .将原先表的ibd文件,拷贝,当前的数据目录下,并修改权限
4 .将原表的数据进行导入alter table t100 import tablespace

innodb的核心特性

事务

事务的ACID特性

事务就是保证交易在计算机(程序)中的完整性

  • 原子性(Atomic): 所有语句作为一个单元全部成功 或全部取消,不能出现中间状态
  • 一致性(Consistent):如果数据库在事务开始时,处于一致状态,则在执行该事务期间保留一致状态
  • 隔离性(isolated): 事务之间不相互影响
  • 持久性(durable): 事务成功之后,所做的所有更改都会准备地记录在数据库中,所做的更改不会丢失。

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

  • 开启事务
    begin
  • 标准的事务语句
    DML: insert update delete
  • 事务结束
    commit 提交
    rollback 回滚(只回滚未提交的)
  • 自动提交机制(autocommit)
    autocommit 默认开启

在线修改autocommit参数

set autocommit = 0      //会话级别(只影响当前会话,及时生效)
set global autocommit =0  //全局级别(窗口断开,重连,才会生效)

配置文件修改

vim /etc/my.cnf
autocommit = 0

事务的隐式提交

  • 触发隐式提交的语句
同一个会话内
begin 开始
DML 
DML
[commit]  触发
[set 命令] 触发
[DDL]   触发
[DCL] 触发
[锁定语句 lock tables和 unlock tables] 触发
[begin]  触发

事务的ACID如何保证

一些概念名词
  • redo log: 重做日志,ib_logfile0~ib_logfileN 轮询使用
  • redo log buffer: 负责redo日志的读和写,redo的内存区域
  • ibd: 存储数据行和索引
  • data buffer pool: 数据缓冲区池,数据和索引缓冲和缓存,ibd的内存区域
  • LSN: 日志序列号(类似于git版本号)存放于磁盘数据页(对应ibd文件),redo文件,data buffer pool,redo buffer,MySQL每此数据库启动,都会比较磁盘数据页(ibd)和redo日志中的LSN,必须要求两者的LSN一致数据库才能启动
  • WAL: 持久化的一种机制。write ahead log, 日志优先于数据写入磁盘
    持久化: 是把内存的数据写入到磁盘
  • 脏页: 内存脏页,内存中发生了修改,没写入到磁盘之前,我们把内存中的数据页称为脏页。即此时ibd里面的LSN好喝data buffer pool中的LSN号不一致
  • ckpt: checkpoints 检查点,就是脏页刷写到磁盘的动作(功能)
  • TXID: 事务号,InnoDB会为每一个事务生成一个事务号,伴随着整个事务周期。直到commit或rollback
redo日志

作用: 主要保证D(持久性) 还为 A (原子性)和 C (一致性)也有作用

  • 记录了什么
    1 .记录了内存数据页的变化
    2 .提供了快速持久化的功能
  1. CSR过程中实现前滚操作(磁盘数据页和redo日志中的LSN号要保持一致)
  • redo日志工作过程
    image.png
  • 为什么把redo buffer写入到redo日志中,就已经commit成功了?

因为data buffer pool 是将ibd中所要修改行的中所在的整个数据页加载上来,进行修改,然后把整个数据页重新写入磁盘。如果进行大量的DML 语句,会加载大量的数据页,写入磁盘时,会造成磁盘IO瓶颈,所以采用redo日志的方式,记录行的变化,写入到磁盘。等数据页达到内存的一个限定值时,就会写入到磁盘

  • 突然断电,导致data buffer pool数据没有写入到ibd中,但以commit成功时

启动MySQL,会检查redo 日志中的LSN 和 ibd中的LSN是否一致,如果不一致,则重新加载idb文件内容,和redo日志中的内容,进行自动故障恢复(ASCR)

自动故障恢复ASCR

1.先把脏页重新构建出来(重新加载idb文件内容,和redo日志中的内容到内存,构建脏页)
2 .构建出脏页后,立即触发ckpt

redo的刷写策略

commit 将redo buffer刷写到redo日志上(redo buffer中可能存在未提交的事务,也会被刷写到redo日志中)

undo

作用: 在ACID特性中,主要保证A(原子性)的特性,同时对C(一致性)和 I(隔离性)也有一定功效
记录了什么

  • 记录了数据修改之前的状态

  • rollback将内存的数据修改恢复到修改之前的

  • 在CSR实现未提交的数据进行回滚操作

  • 实现一致性快照,配合锁机制,隔离级别,保证MVCC读和写的操作,不会相互阻塞


    image.png
  • 当redo buffer存在未提交的事务,也被刷到磁盘上,时断电情况

当redo日志,存在未提交事务时,会给此事务(TXID)打上未提交的标签,然后对比undo日志的TXID,从undo日志加载出来原先数据,到undo buffer中,进行回滚。最终保持了,ibd和redo日志中的LSN号一致

实现了事务之间的隔离功能
innodb中实现了行级锁
row-level lock
gap 锁
next-lock

隔离级别
  • 查看隔离级别
    SELECT @@tx_isolation;
  • RU: 读未提交,可脏读(当事务没有提交时,就能读到内存中的数据)
    例: 当你去银行取钱,还没点确定时。老婆在家查余额,就发现少钱了
  • RC: 读以提交,可能出现幻读,可防止脏读,不可重复读,总是读到最新数据
    例: 银行在做月结的时候 2020/01/31 23:59:59,当这个查询持续5分钟,但银行的业务并不会停止,做完查询可能就会读到2月份的数据,并且每次查询结果都不一样。
  • RR: 可重复读,功能是防止幻读现象,利用的是undo的快照技术和GAP(间隙锁)+Nextlock(下键锁)
    可重复读: 是有MVCC实现的
    MVCC: 使用undo快照,MVCC在每一个会话开启是,都会生成一致性快照,将来读取的时候都会去读这个快照的数据。所谓的多版本控制,就是开启了多个会话,提供了多个undo快照版本。直接commit会重新起一个新的会话
    幻读: 在两个会话中,第一个修改ID>2的name值为zs,但是在第二个会话中,插入一个ID为10,name列为ls,此时第一个会话正在修改,第二个会话的事务已经提交,在第一个会话中查询会发现ID为10的列没有修改。
    防止幻读:在RR模式下,GAP+next-lock进行避免幻读现象,必须有索引支持
  • SR: 可串行化,可以防止死锁,但是连接并发事务差
    补充: 在RC级别下,卡哇伊减轻GAP+nextlock锁的问题,但是会出现幻读现象,一般为了读一致性,会在正常的select后,添加for update语句。但是,请牢记执行完一定要加commit,否则容易出现死锁

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
# 控制redo buffer和data buffer pool的刷写策略
innodb_flush_method=O_DIRECT
# redo 日志相关
innodb_log_buffer_size=16777216 (redo buffer 大小)
innodb_log_file=50331648     (innodb文件大小)
innodb_log_files_in_group=3 (redo 日志的个数)
# 脏页刷写策略
innodb_max_dirty_pages_pct=75
最大脏页占用内存比例75%,即data buffer 写入到data的限制
还有哪些机制触发写磁盘?
CSR(自动故障恢复)
redo 满了
image.png
  • innodb_flush_log_at_trx_commit=0 是指redo buffer 刷到os buffer 是每秒进行一次,从os buffer 到 data 也是每秒进行一次。一秒出现无数次事务,如果宕机,会造成一秒数据丢失
  • innodb_flush_log_at_trx_commit=1 是指redo buffer 刷到 os buffer 每commit 进行一次,os buffer 到 data 也是每进行一次commit进行一次
  • innodb_flush_log_at_trx_commit=2 从redo buffer 刷到 os buffer 每commit进行一次,从 os buffer 刷到 data 每秒进行一次

在追求性能的结构中,可以设置为innodb_flush_at_trx_commit=0 ,比如监控系统。

redo buffer 和data buffer 刷写策略

fsync(默认)

fsync.png

fsync是由redo buffer和data buffer pool 刷到os buffer,再由os buffer 刷到 data。因为redo buffer 和data buffer pool 都是 在内存,fsync这种模式可能会给内存造成压力

O_DIRECT(推荐)

image.png

O_DIRECT是redo buffer直接刷到data,data buffer pool先刷到os buffer,再由os buffer 刷到data

O_DSYNC

image.png

O_DSYNC是把redo buffer直接刷到 data,data buffer pool 刷到os buffer,再由os buffer 刷到data

最高安全模式

innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT

最高性能模式

innodb_flush_log_at_trx_commit=1
innodb_flush_method=fsync

概述redo日志和undo日志

redo 日志

  • 记录了数据页的变化
  • 提供了事务的commit特性
  • 在CSR中实现了前滚

undo日志

  • 记录了数据修改之前的数据
  • 提供了事务的rollback
  • 在CSR中实现了回滚

你可能感兴趣的:(存储引擎)