存储引擎及日志深入详解

一、存储引擎

1. mysql的存储引擎

01)InnoDB
    适合数据增删改查
02)MyISAM
    存储一些只读的数据
03)MEMORY 
    支持hash索引
04)ARCHIVE
05)FEDERATED
06)EXAMPLE
07)BLACKHOLE
08)MERGE
09)NDBCLUSTER
10)CSV

#还可以使用第三方存储引擎:
MySQL当中插件式的存储引擎类型
MySQL的两个分支:
1.perconaDB
2.mariaDB

#查看存储引擎
mysql> show engines;

2. innodb和myisam的区别

#MyISAM:
不支持事务,但是每次查询都是原子的;
支持表级锁,即每次操作是对整个表加锁;
物理文件有三个
不支持热备
#InnoDb:
支持MVCC多事物并发控制
支持ACID的事务,支持事务的四种隔离级别;
支持行级锁:因此可以支持写并发;
物理文件有两个
支持热备
支持自动故障恢复
多缓冲区池
支持外键(不推荐使用)

#myisam存储引擎
-rw-rw---- 1 mysql mysql  10684 7月   9 15:10 user.frm       #表结构
-rw-rw---- 1 mysql mysql    980 7月  15 09:14 user.MYD       #数据文件
-rw-rw---- 1 mysql mysql   2048 7月  15 09:28 user.MYI       #索引文件

#innodb存储引擎
-rw-rw---- 1 mysql mysql   8710 7月  17 10:59 city.frm       #表结构
-rw-rw---- 1 mysql mysql 950272 7月  17 10:59 city.ibd       #表空间(数据和索引)

#查看时用strings
[root@db03 ~]# strings /usr/local/mysql/data/world/stu.frm
------------------------------------------------------
# innodb核心特性
MVCC:一种并发控制的方法,在数据库管理系统中,实现对数据库的并发访问;
支持事务
行级锁         #innodb支持行级锁,myiasm支持表级锁
热备份         #innodb支持热备,myisam不支持热备
自动故障恢复 Crash Safe Recovery

3. 存储引擎相关命令

1)查看当前数据库的存储引擎

mysql> SELECT @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set (0.00 sec)

2)查看表的存储引擎

mysql> use information_schema 

#查看哪些表是innodb存储引擎
mysql> select TABLE_SCHEMA,TABLE_Name,ENGINE from tables where ENGINE='innodb';

#查看哪些表时myisam存储引擎
mysql> select TABLE_SCHEMA,TABLE_Name,ENGINE from tables where ENGINE='myisam';

#查看表信息
mysql> select * from information_schema.tables where table_name='test11'\G
#查看指定表的存储引擎
mysql> show create table city;

#查看列信息
mysql> select * from COLUMNS where COLUMN_NAME='name'\G

3)修改存储引擎

#临时设置
mysql> set @@default_storage_engine=myisam;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| MyISAM                   |
+--------------------------+

#永久修改
[root@db03 mysql]# vim /etc/my.cnf
[mysqld]
default_storage_engine=myisam

#建表时指定存储引擎
mysql> create table innodb(id int) ENGINE=innodb;

4. Innodb 存储引擎

  • 核心特性

表空间介绍

5.5版本以后出现共享表空间概念
表空间的管理模式的出现是为了数据库的存储更容易扩展
5.6以后版本中默认的是独立表空间

# 查看表空间模式:
mysql> select @@innodb_file_per_table;
+-------------------------+
| @@innodb_file_per_table |
+-------------------------+
|                       1 |
+-------------------------+
1代表独立表空间模式,0代表共享表空间模式.
5.5版本后都可以切换表空间模式.
mysql> set global innodb_file_per_table=1;
只对设置之后的新文件生效.

共享表空间(ibdata1)

1)# 存储的内容:
1.1 系统数据
1.2 undo            undo log日志,事务日志
1.3 临时表

2)# 概念
2.1.优点:
    可以将表空间分成多个文件存放到各个磁盘上(表空间文件大小不受表大小的限制,如一个表可以分布在不同的文件上)。
    数据和文件放在一起方便管理。

2.2.缺点:
    所有的数据和索引存放到一个文件中,虽然可以把一个大文件分成多个小文件,但是多个表及索引在表空间中混合存储,
    这样对于一个表做了大量删除操作后表空间中将会有大量的空隙,特别是对于统计分析,日志系统这类应用最不适合用共享表空间。

3)# 配置共享表空间
[root@db03 data]# vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:76M;tmp/ibdata2:50M:autoextend

4)# 查看共享表空间
mysql> show variables like '%path%';
+----------------------------------+----------------------------------------+
| Variable_name                    | Value                                  |
+----------------------------------+----------------------------------------+
| innodb_data_file_path            | ibdata1:76M;tmp/ibdata2:50M:autoextend |

独立表空间 *.ibd

1)# 概念
对于用户自主创建的表,会采用此种模式,每个表由一个独立的表空间进行管理
1.1.优点:
    1)每个表都有自己独立的表空间
    2)数据分开存储
1.2.缺点:
    1)单表空间不能过大,不能大于100G

查看独立表空间

#物理查看
[root@db01 ~]# ll /application/mysql/data/world/
-rw-rw---- 1 mysql mysql 688128 Aug 14 16:23 city.ibd

#命令行查看是否开启独立表空间
mysql> show variables like '%per_table%';
innodb_file_per_table=ON

移除和导入表空间数据的命令

#1.移除表的表空间数据 (会物理删除city_new.ibd文件)
mysql> alter table city_new discard tablespace;

#2.表读取表空间数据(需要存在city_new.ibd文件)
mysql> alter table city_new import tablespace;

5. Innodb核心 - 事务

1.)什么是事务(transaction)?

主要针对DML语句(update,delete,insert)
1.一组数据操作执行步骤,这些步骤被视为一个工作单元:
    1)用于对多个语句进行分组
    2)可以在多个客户机并发访问同一个表中的数据时使用
2.所有步骤都成功或都失败
    1)如果所有步骤正常,则执行
    2)如果步骤出现错误或不完整,则取消

2.)事务的演示

# 首先改变mysql的提交模式
set autocommit=0; 禁止自动提交
set autocommit=1; 开启自动提交

1)成功事务
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;
2)事务回滚
mysql> begin;
mysql> update stu set name='zhang3';
mysql> delete from stu;
mysql> rollback;

'!注意!只针对DML语句,对于删除库表等其他语句无效。'

3.)事务的特性(ACID)

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

4.)事务的控制语句

START TRANSACTION(或 BEGIN): # 显式开始一个新事务
SAVEPOINT: # 分配事务过程中的一个位置,以供将来引用
'存储点可以设置多个,命令为: savepoint 位置点名   '
COMMIT: # 永久记录当前事务所做的更改
ROLLBACK: # 取消当前事务所做的更改
ROLLBACK TO SAVEPOINT: # 取消在 savepoint 之后执行的更改
RELEASE SAVEPOINT: # 删除 savepoint 标识符
SET AUTOCOMMIT: # 为当前连接禁用或启用默认 autocommit 模式

5.)事务的自动提交

#临时设置关闭
mysql> set autocommit=0;
Query OK, 0 rows affected (0.02 sec)

#永久设置关闭
[root@db01 world]# vim /etc/my.cnf
[mysqld]
autocommit=0

6. 事务的日志

1.)redo log

# 物理文件存放于ib_logfile0,ib_logfile1名称存在
'文字描述流程'
#修改
1)begin语句开始后,首先将表中命令id=1的行所在数据页加载到内存中data buffer page
2)MySQL实例在内存中将id=1的数据页改成id=2
3)id=1变成id=2的变化过程会记录到,redo内存区域,也就是redo buffer page中
4)当敲下commit命令的瞬间,MySQL会将redo buffer page写入磁盘区域redo log
5)当写入成功之后,commit返回ok

#查询
1.首先将表中id=1的行所在数据页加载到内存中data buffer page
2.将redo log中id=1变成id=2的变化过程取加载到redo buffer page
3.通过data buffer page和redo buffer page得到一个结果

2.)undo log

# 物理文件存于ibdata1,ibdata2
1)作用
undo,顾名思义“回滚日志”,是事务日志的一种
在事务ACID过程中,实现的是“A”原子性的作用。当然CI的特性也和undo有关

UOTUaj.jpg

3.)redo和undo的存储位置

#redo位置
[root@db01 data]# ll /application/mysql/data/
-rw-rw---- 1 mysql mysql 50331648 Aug 15 06:34 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 Mar  6  2017 ib_logfile1

#undo位置
[root@db01 data]# ll /application/mysql/data/
-rw-rw---- 1 mysql mysql 79691776 Aug 15 06:34 ibdata1
-rw-rw---- 1 mysql mysql 79691776 Aug 15 06:34 ibdata2

4.)redo log、undo log和二进制日志bin log的区别

1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。

2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。

当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。

但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。

通过undo log记录delete和update操作的结果发现:(insert操作无需分析,就是插入行而已)

delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。

update分为两种情况:update的列是否是主键列。
如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。
如果是主键列,update分两部执行:先删除该行,再插入一行目标行。

7. 事务中的锁

1.什么是锁
“锁”顾名思义就是锁定的意思。

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

3.锁的类别
排他锁:保证在多事务操作时,数据的一致性。(在我修改数据时,其他人不得修改)
共享锁:保证在多事务工作期间,数据查询时不会被阻塞。

乐观锁:多实务操作时,数据可以同时修改,谁先提交,以谁为准
悲观锁:多实务操作时,数据只有一个人可以修改

4.多版本并发控制
   1.) 只阻塞修改类操作(排他锁),不阻塞查询类操作(共享锁)
   2.) 乐观锁的机制(谁先提交谁为准)

5.锁的粒度
   1.) MyIsam:表级锁
   2.) Innodb:行级锁

8. 事务中的隔离级别

1.)四种隔离级别

1.RU级别:READ UNCOMMITTED(独立提交):未提交读,允许事务查看其他事务所进行的未提交更改

2.RC级别:READ COMMITTED:允许事务查看其他事务所进行的已提交更改,查看不需要重新记入数据库

3.RR级别:REPEATABLE READ:允许事务查看其他事务所进行的已提交更改,查看数据需要重新进入数据库(InnoDB 的默认级别)

4.串行化:SERIALIZABLE:将一个事务的结果与其他事务完全隔离

2.)查看隔离级别

#查看隔离级别
mysql> show variables like '%iso%';

3.)设置隔离级别

1)设置RU级别
[root@db03 ~]# vim /etc/my.cnf
transaction_isolation=read-uncommit

2)设置RC级别
[root@db03 ~]# vim /etc/my.cnf
transaction_isolation=read-commit

4.)名词

1.脏读:RU级别,执行事务修改数据,被读取,但是数据最终回滚了,查询到的数据就是脏读

2.幻读:删除所有表数据,删除的同时有人插入数据,查看数据时以为是没删干净

3.不可重复读:修改数据后被读取,被读取之后再次修改数据,两次数据不一致

5.)如何解决脏读,幻读,不可重复读的问题?

1.RU:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

2.RC:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

3.RR:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

4.串行化:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。


二、经典实际生产故障案例及解决

1.故障

2.解决方案和步骤

# 报错注意: import导入的数据ibd文件需要授权mysql.mysql权限后才能导入.

三、InnoDB关键特性之double write

两次写的原理机制
  1、解决问题
  2、使用场景
  3、doublewrite的工作流程
  4、崩溃恢复

1.脏页刷盘风险

关于IO的最小单位:
  1、数据库IO的最小单位是16K(MySQL默认,oracle是8K)
  2、文件系统IO的最小单位是4K(也有1K的)
  3、磁盘IO的最小单位是512字节
因此,存在IO写入导致page损坏的风险:

2.doublewrite:两次写

提高innodb的可靠性,用来解决部分写失败(partial page write页断裂)。

1、Double write解决了什么问题
  一个数据页的大小是16K,假设在把内存中的脏页写到数据库的时候,写了2K突然掉电,也就是说前2K数据是新的,后14K是旧的,那么磁盘数据库这个数据页就是不完整的,是一个坏掉的数据页。redo只能加上旧、校检完整的数据页恢复一个脏块,不能修复坏掉的数据页,所以这个数据就丢失了,可能会造成数据不一致,所以需要double write。

2、使用情景
  当数据库正在从内存想磁盘写一个数据页是,数据库宕机,从而导致这个页只写了部分数据,这就是部分写失效,它会导致数据丢失。这时是无法通过重做日志恢复的,因为重做日志记录的是对页的物理修改,如果页本身已经损坏,重做日志也无能为力。

3、double write工作流程

  doublewrite由两部分组成,一部分为内存中的doublewrite buffer,其大小为2MB,另一部分是磁盘上共享表空间(ibdata x)中连续的128个页,即2个区(extent),大小也是2M。

  1)当一系列机制触发数据缓冲池中的脏页刷新时,并不直接写入磁盘数据文件中,而是先拷贝至内存中的doublewrite buffer中;

  2)接着从两次写缓冲区分两次写入磁盘共享表空间中(连续存储,顺序写,性能很高),每次写1MB;

  3)待第二步完成后,再将doublewrite buffer中的脏页数据写入实际的各个表空间文件(离散写);(脏页数据固化后,即进行标记对应doublewrite数据可覆盖)

4、doublewrite的崩溃恢复

  如果操作系统在将页写入磁盘的过程中发生崩溃,在恢复过程中,innodb存储引擎可以从共享表空间的doublewrite中找到该页的一个最近的副本,将其复制到表空间文件,再应用redo log,就完成了恢复过程。

  因为有副本所以也不担心表空间中数据页是否损坏。

Q:为什么log write不需要doublewrite的支持?

A:

  因为redolog写入的单位就是512字节,也就是磁盘IO的最小单位,所以无所谓数据损坏。

3.doublewrite的副作用

1、double write带来的写负载

  1)double write是一个buffer, 但其实它是开在物理文件上的一个buffer, 其实也就是file, 所以它会导致系统有更多的fsync操作, 而硬盘的fsync性能是很慢的, 所以它会降低mysql的整体性能。

  2)但是,doublewrite buffer写入磁盘共享表空间这个过程是连续存储,是顺序写,性能非常高,(约占写的%10),牺牲一点写性能来保证数据页的完整还是很有必要的。

2、监控double write工作负载

mysql> show global status like '%dblwr%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Innodb_dblwr_pages_written | 7     |
| Innodb_dblwr_writes        | 3     |
+----------------------------+-------+

关注点:Innodb_dblwr_pages_written / Innodb_dblwr_writes

  开启doublewrite后,每次脏页刷新必须要先写doublewrite,而doublewrite存在于磁盘上的是两个连续的区,每个区由连续的页组成,一般情况下一个区最多有64个页,所以一次IO写入应该可以最多写64个页。

  而根据以上系统Innodb_dblwr_pages_written与Innodb_dblwr_writes的比例来看,大概在3左右,远远还没到64(如果约等于64,那么说明系统的写压力非常大,有大量的脏页要往磁盘上写),所以从这个角度也可以看出,系统写入压力并不高。

3、关闭double write适合的场景
  1、海量DML
  2、不惧怕数据损坏和丢失
  3、系统写负载成为主要负载

mysql> show variables like '%double%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| innodb_doublewrite | ON    |
+--------------------+-------+

  作为InnoDB的一个关键特性,doublewrite功能默认是开启的,但是在上述特殊的一些场景也可以视情况关闭,来提高数据库写性能。静态参数,配置文件修改,重启数据库。

4、为什么没有把double write里面的数据写到data page里面呢?

  1)double write里面的数据是连续的,如果直接写到data page里面,而data page的页又是离散的,写入会很慢。

  2)double write里面的数据没有办法被及时的覆盖掉,导致double write的压力很大;短时间内可能会出现double write溢出的情况。

Copyright © 2009 - Now . XPBag.com . All rights Reserved.
夜心的小站 » 存储引擎及日志深入详解

发表评论

提供最优质的资源集合

立即查看 了解详情