存储引擎

六 存储引擎

1. 什么是存储引擎

相当于MYSQL内置的文件系统。与Linux中的文件系统打交道的层次结构。

2. MYSQL存储引擎种类

2.1 官方:Oracle MYSQL

可以给不同的表,设定不同的存储引擎。

列举MYSQL中支持存储引擎的种类?

InnoDB :MYSQL5.5版本以后默认的存储引擎。99%以上的业务表都是它。

MyISAM :

CSV :

MEMORY :

2.2 其他分支

percona :XtraDB

MariaDb :InnoDB

其他的引擎:

TokuDB,MyRocks

Compression:25x for high compression 优点:压缩比高(也就是说节省空间)。

Fast Insertions(插入) and Deletions(删除) 优点:插入删除效能高

适合于,业务当中有大量插入或者删除操作的场景。

应用于,数据量较大的业务。

 

3.InnoDB 核心特性

3.1 介绍

MVCC :Muti-Version Concurrency Control多版本并发控制。

Clustered index:聚簇索引

多缓冲区池

事物

行级锁

外键

更多复制特性

支持热备

自动故障恢复

Change buffer:修改缓冲区

自适应hash索引:AHI(adpater hash index)

自动故障恢复

3.2 存储引擎的管理命令

3.2.1 使用SELECT 确认会话存储引擎

SELECT @@default_storage_engine;

3.2.2 存储引擎(不代表生产操作)

会话级别:

SET default_storage_engine=MYISAM;

SET default_storage_engine=INNODB;

全局级别(仅影响新会话):

SET GLOBAL default_storage_engine=MYISAM

重启之后,所有参数均失败。

如果要永久生效:

写入配置文件:

vi /etv/my.cnf

[mysqld]

default_storage_engine=MYISAM

存储引擎是表记表级别的,每个表创建时可以指定不同的存储引擎,但我们建议统一为InnoDB.

3.2.3 show确认每个表的存储引擎;

SHOW CREATE TABLE sc\G;

\G分行。

SHOW TABLE STATUS LIKE 'sc'\G

3.2.4 确认每个表的存储引擎

SELECT table_schema,table_name,ENGINE

FROM information_schema.tables

WHERE table_schema NOT IN('sys','mysql','information_schema','performance_schema');

SHOW STATUS;

3.2.4 修改一个表的存储引擎

USE school;

ALTER TABLE sc ENGINE=MYISAM;

SHOW CREATE TABLE sc;

ALTER TABLE sc ENGINE=InnoDB;

注意:此命令我们经常使用他,进行innodb表的碎片整理。(经常的删除数据就会产生碎片,影响性能)。

USE information_schema;

[SELECT TABLE_SCHEMA,

TABLE_NAME,

TABLE_ROWS,

DATA_LENGTH,

INDEX_LENGTH,

CONCAT(ROUND(DATA_FREE / 1024 / 1024, 2), 'M') AS datafree

FROM information_schema.tables t

WHERE TABLE_SCHEMA NOT IN ('sys','information_schema','mysql','performance_schema');]==肯定会经常用到。

3.2.5 平常处理过的Mysql问题--碎片处理(ALTER TABLE sc ENGINE=InnoDB;)

环境:Centos7.4 MySQL 5.7.26,InnoDB存储引擎。

业务特点:数据量级较大,经常需要按月删除历史数据。

问题:磁盘空间占用很大,不释放。

处理方法:

以前:将数据逻辑导出,手工drop表,然后倒入进去。

现在:

对表进行按月进行分表(partition,中间件)或者归档表(pt-archive)

业务替换为truncate

3.2.6 拓展:如何批量修改

需求1:将zabbix库中的所有表,innoDB替换为tokudb

SELECT CONCAT("ALTER TABLE school.",table_name," ","ENGINE=CSV;")

FROM information_schema.tables

WHERE table_schema='school' INTO OUTFILE '/tmp/toku.sql';

改回去

SELECT CONCAT("ALTER TABLE school.",table_name," ","ENGINE=InnoDB;")

FROM information_schema.tables

WHERE table_schema='school' INTO OUTFILE '/tmp/toku.sql';

需求2 将所有非InnoDB业务表查询出来,并修改为InnoDB

SELECT CONCAT("alter table ",table_schema,".",table_name,"engine=innodb;")

FROM information_schema.tables

WHERE ENGINE != 'InnoDB'

AND table_schema

NOT IN ('sys','information_schema','mysql','performance_schema')

INTO OUTFILE '/tmp/alter.sql';

4.MYSQL 存储引擎体系结构

4.1 宏观结构

4.1.1 MyISAM

myt.frm : 数据字典信息(列的定义和属性)

myt.MYD : 数据行

myt.MYI : 索引

4.1.2 InnoDB

city.frm: 数据字典信息(列的定义和属性)

city.ibd: 数据行和索引

ibdata1 : 数据字典信息,UNDO,double write 磁盘区域,change buffer 磁盘区域。

说明:不同版本ibdata1中存储的数据不一样。

ibdata1:

5.5V: ibdata1 中还会存储临时表数据 + 用户数据(数据行+索引)

3.InnoDB 核心特性

3.1 介绍

MVCC :Muti-Version Concurrency Control多版本并发控制。

Clustered index:聚簇索引

多缓冲区池

事物

行级锁

外键

更多复制特性

支持热备

自动故障恢复

Change buffer:修改缓冲区

自适应hash索引:AHI(adpater hash index)

自动故障恢复

3.2 存储引擎的管理命令

3.2.1 使用SELECT 确认会话存储引擎

SELECT @@default_storage_engine;

3.2.2 存储引擎(不代表生产操作)

会话级别:

SET default_storage_engine=MYISAM;

SET default_storage_engine=INNODB;

全局级别(仅影响新会话):

SET GLOBAL default_storage_engine=MYISAM

重启之后,所有参数均失败。

如果要永久生效:

写入配置文件:

vi /etv/my.cnf

[mysqld]

default_storage_engine=MYISAM

存储引擎是表记表级别的,每个表创建时可以指定不同的存储引擎,但我们建议统一为InnoDB.

3.2.3 show确认每个表的存储引擎;

SHOW CREATE TABLE sc\G;

\G分行。

SHOW TABLE STATUS LIKE 'sc'\G

3.2.4 确认每个表的存储引擎

SELECT table_schema,table_name,ENGINE

FROM information_schema.tables

WHERE table_schema NOT IN('sys','mysql','information_schema','performance_schema');

SHOW STATUS;

3.2.4 修改一个表的存储引擎

USE school;

ALTER TABLE sc ENGINE=MYISAM;

SHOW CREATE TABLE sc;

ALTER TABLE sc ENGINE=InnoDB;

注意:此命令我们经常使用他,进行innodb表的碎片整理。(经常的删除数据就会产生碎片,影响性能)。

USE information_schema;

[SELECT TABLE_SCHEMA,

TABLE_NAME,

TABLE_ROWS,

DATA_LENGTH,

INDEX_LENGTH,

CONCAT(ROUND(DATA_FREE / 1024 / 1024, 2), 'M') AS datafree

FROM information_schema.tables t

WHERE TABLE_SCHEMA NOT IN ('sys','information_schema','mysql','performance_schema');]==肯定会经常用到。

3.2.5 平常处理过的Mysql问题--碎片处理(ALTER TABLE sc ENGINE=InnoDB;)

环境:Centos7.4 MySQL 5.7.26,InnoDB存储引擎。

业务特点:数据量级较大,经常需要按月删除历史数据。

问题:磁盘空间占用很大,不释放。

处理方法:

以前:将数据逻辑导出,手工drop表,然后倒入进去。

现在:

对表进行按月进行分表(partition,中间件)或者归档表(pt-archive)

业务替换为truncate

3.2.6 拓展:如何批量修改

需求1:将zabbix库中的所有表,innoDB替换为tokudb

SELECT CONCAT("ALTER TABLE school.",table_name," ","ENGINE=CSV;")

FROM information_schema.tables

WHERE table_schema='school' INTO OUTFILE '/tmp/toku.sql';

改回去

SELECT CONCAT("ALTER TABLE school.",table_name," ","ENGINE=InnoDB;")

FROM information_schema.tables

WHERE table_schema='school' INTO OUTFILE '/tmp/toku.sql';

需求2 将所有非InnoDB业务表查询出来,并修改为InnoDB

SELECT CONCAT("alter table ",table_schema,".",table_name,"engine=innodb;")

FROM information_schema.tables

WHERE ENGINE != 'InnoDB'

AND table_schema

NOT IN ('sys','information_schema','mysql','performance_schema')

INTO OUTFILE '/tmp/alter.sql';

4.MYSQL 存储引擎体系结构

4.1 宏观结构

4.1.1 MyISAM

myt.frm : 数据字典信息(列的定义和属性)

myt.MYD : 数据行

myt.MYI : 索引

4.1.2 InnoDB

city.frm: 数据字典信息(列的定义和属性)

city.ibd: 数据行和索引

ibdata1 : 数据字典信息,UNDO,double write 磁盘区域,change buffer 磁盘区域。

说明:不同版本ibdata1中存储的数据不一样。

ibdata1:

5.5V: ibdata1 中还会存储临时表数据 + 用户数据(数据行+索引)

5.6V: ibdata1 中还会存储临时表数据

8.0V: ibdata1 取消存储 数据字典信息,undo独立了。

可以理解为,MYSQL在慢慢瘦身ibdata1共享表空间,把比较关键的数据独立出来了。

UNDO (事物回滚日志)

ib_logfile0_logfileN : InnoDB 事物重做日志(redo log)

ibtmp1:临时表空间文件(排序,分组,多表连接,子查询,逻辑备份等。)

ib_buffer_pool:正常关库的时候,存储缓冲区的热数据。

所以:InnoDB的表,仅仅是拷贝ibd和frm文件到新的数据库,是无法正常使用。

4.2 InnoDB 微观结构

4.2.1 磁盘

1.什么是表空间?

表空间概念是引入于Oracle数据库。

起初为 MYSQL5.5 版本引入了共享表空间模式。

2.MYSQL表空间类型

The System Tablespace:共享表空间:在5.5版本引入了共享表空间(ibdata1),作为默认的存储方式。

File-Per-Table Tablespaces:独立表空间: 5.6 版本默认独立表空间模式。单表单表空间。

General Tablespaces:普通表空间:完全和Oracle一致的表空间管理模式

Undo Tablespaces:undo表空间:存储undo logs (回滚日志)

The Temporary Tablespace:临时表空间:存储临时表。5.7 默认独立。

3.表空间管理

用户数据默认的存储方式,独立表空间。独立表空间和共享表空间是可以互相切换的。

-- 查看默认表空间模式?

mysql>select @@innodb_file_per_table=0;

重新登录会话:

mysql>select @@innodb_file_per_table;

说明:修改完成之后,只影响新创建的表。

-- 如何切换?

临时:

mysql>set global innodb_file_per_table=0;

重新登录会话:

永久:

vim /etc/my.cnf

innodb_file_per_table=0

-- 验证

mysql>select @@innodb_file_per_table;

说明:修改完成之后,只影响新创建的表。

-- 如何扩展共享表空间大小和个数?

说明:通常是在初始化数据时,就设定好参数。

方法1:初始化之前,需要在my.cnf加入以配置即可:

innodb_data_file_path=ibdata1:1G;ibdata2:1G;autoextend

方法2:已运行的数据库上扩展多个ibdata文件

错误方式:

解决方法,在设置innodb_data_file_path参数时,已有的ibdata1文件大小应该和磁盘上真实大小一致,而不是随便指定的,正确的调整方式

innodb_data_file_path=ibdata1:76M;ibdata2:128M;ibdata3:128M :autoextend

事物日志 :

redo log 重做日志

(1)文件位置

/data/3306/ib_logfile0--ib_logfileN

(2) 控制参数:

innodb_log_file_size=50331648; #设置文件大小

innodb_log_files_group=2

#设置文件个数

innodb_log_group_home_dir=./设置存储位置。

(3)功能:用来存储,mysql在做修改类(DML)操作时的《数据页变化》过程及版本号(LSN),属于物理日志。

默认两个文件存储redo,是循环覆盖使用的。

undo logs 回滚日志

(1)文件位置:(5.7默认位置)

ibdataN

ibtmp

mysql> show variables like '%undo%';

+--------------------------+------------+

| Variable_name | Value |

+--------------------------+------------+

| innodb_max_undo_log_size | 1073741824 |

| innodb_undo_directory | ./ |

| innodb_undo_log_truncate | OFF |

| innodb_undo_logs | 128 |

| innodb_undo_tablespaces | 0 |

+--------------------------+------------+

(2)参数:

innodb_rollback_segments=128 #回滚段的个数

(3)功能

用来存储回滚日志,可以理解为记录了每次操作的反操作,属于逻辑日志。

# 使用快照功能 提供InnoDB多版本并发读写。

# 通过记录的反操作,提供回滚功能。(我的理解相当于ctrl + z)

HP UNIX最牛批的技术LVM。

5 内存

(1) 数据内存区域:

(1.1) 共享内存缓冲区池:

参数:

mysql> show variables like '%buffer_pool%';

功能:缓冲数据页 + 索引页

(1.2)会话内存缓冲区

join_buffer_size

key_buffer_size

read_buffer_size

read_rnd_buffer_size

sort_buffer_size

(2)日志

innodb_log_buffer_size=167777216

功能:负责redo日志的缓冲。

案例:

背景:

1.硬件:联想服务器(IBM) 磁盘500G 没有raid

2.软件环境:Centos 6.8 Mysql 5.6.33 innodb引擎 独立表空间

3.备份没有,日志也没开

4.开发用户专用库:jira(bug追踪)、confluence(内部知识库) ------>LNMT

5.故障描述:

断电了,启动完成后"/"只读

fsck 重启,系统成功后,mysql启动不了。

结果:conulence库在,jira库不见了

求助:

这种情况怎么恢复?

我问:

有备份没

求助:

连二进制日志都没有,没有备份,没有主从

我说:

没招了,jira需要硬盘恢复了。

求助:

1.jira问题拉到中关村了

2.能不能暂时把confulence库先打开用着

将生产库confluence,拷贝到1:1虚拟机/var/lib/mysql,直接访问时访问不了的

问:有没有工具能直接读取ibd

我说:我查查,最后发现没有

idea

表空间迁移:

(1) 创建一个一模一样的t1空表

create table xxx

(2) 删掉空表的表空间 ibd

alter table confulence.t1 discard tablespace;

(3) 拷贝准备好的ibd,赋权,导入表空间到t1表

alter table confulence.t1 import tablespace;

虚机测试可行。

处理问题思路:confulence库中一共有107张表。

1.创建107张和原来一模一样的表。

他有2016年的历史库,我让他去他同事的电脑上 mysqldump备份confulence库

mysqldump -uroot -ppassw0rd -B

confulence --no-data >test.sql

拿到你的测试库,进行恢复

到这步为止,表结构有了。

2.表空间删除

select concat('alter table ',table_schema,'.'table_name ' discard tablespace;')

from information_schema.tables

where table_schema='confluence'

into outfile '/tmp/discard.sql';

source /tmp/discard.sql

在执行过程中发现,有20-30个表无法成功。因为主外键的关系

很绝望,一个表一个表的分析表结构很痛苦。

set foreign_key_checks=0 跳过了外键检查。

3.拷贝生产中confulence库下的所有表的ibd文件拷贝到准备好的环境中

select concat('alter table',table_scema,'.',table_name,'import tablespace;')

from information_schema

where table_schema='confulence'

into outfile '/tmp/import.sql';

source /tmp/import.sql

4.验证数据

表都可以访问了,数据挽回到了出现问题时刻的状态。

问:2亿行的表,想要删除其中1000w的表,你们公司是怎么做的,加入是按照时间列条件。

回答:

1.如果2亿的数据表,还没有生成,建议在设计表时,采用分区表的方式(按月range),然后删除时truncate。

2.如果2亿行数据表,已经存在,建议使用pt-archive 工具进行归档表,并且删除无用数据。

MYSQL总共使用的内存=共享+会话内存*会话个数+额外的内存使用(文件系统缓存)

6 InnoDB 核心特性详解

6.1 事务

6.1.1 什么是事务?

事务是伴随着《交易类》的业务场景出现的工作机制。保证交易的“和谐”。

交易?

现实:

物换物 :麦子换面粉,豆子换豆腐。

货币换物 :实物货币换货品,虚拟货币换货物。

计算机中:

例如: A 发红包 B

开启事物。

A账户(100元) :(update) A-100元

B账户 (0元) :(update) B+100元

事物结束

1.1.2 事务ACID标准特性

A (automicity) :原子性

原子是物质的最小构成单元,具备不可再分的特性。

在一个事务工作单元中,所有标准事务语句(DML),要么全成功,要么回滚。

C (consistency):一致性

事务发生前,中,后都应该保证数据是始终一致状态。

MYSQL的各项功能的设计,都是最终要保证一致性。

I (isolation) :隔离性

MYSQL 可以支持多事务

A工作的时候,不能受到其他事务的影响。

D (durability) :持久性

当事务提交(Commit命令执行成功后),此次事务操作的 操作所有数据"落盘",都要永久保存下去。

不会因为数据实例发生故障,导致数据失败。

1.1.3 事务生命周期管理

标准的事务控制语句

BEGIN / START TRANSACTION :开启事务

COMMIT :提交事务

ROLLBACK :回滚事务

标准的事务语句 :

INSERT

UPDATE

DELETE

SELECT

BEGIN;

DML1

标签1

DML2

标签2

DNL3

标签3

ROLLBACK;

(3)自动提交功能

mysql> SELECT @@autocommit;

+--------------+

| @@autocommit |

+--------------+

| 1 |

+--------------+

在autocommit=1的时候,没有加begin(没有显示的开启事务)。

在你执行dml语句时,会自动在这个DML之前加一个begin,

BEGIN;----> 自动

DELETE ......

COMMIT; ----> 自动

应用场景

autocommit=1,一般合适于非交易类业务场景。

如果时交易类的业务:

方案1:

autocommit=0; COMMIT,手动提交才生效。

方案2:

autocommit=0;

每次想要发生事务型操作。

BEGIN 和 COMMIT 都手工操作。

设置方法:

(1)临时生效:

mysql>SET GLOBAL autocommit=0;

重新开启会话生效。

(2)永久生效

vim /etc/my.cnf

autocommit=0

重启数据库生效。

(4)隐式事务控制语句

隐式提交:

1.设置了autocommit=1

2.DDL,DCL等非DML语句时,会触发隐式提交

SESSION 1:

begin;

DML1

DML2

COMMIT;

DROP DATABASE world;

导致提交的事务语句:

DDL语句:(alter CREATE 和drop)

DCl : (grant REVOKE 和set password)

锁定语句: (LOCK TABLES 和 UNLOCK tables)

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

TRUNCATE TABLE

LOAD DATA INFILE

SELECT FOR UPDATE

隐式回滚:

会话关闭

数据库宕机

事务语句执行失败

1.2 InnoDB事务的ACID如何保证?

1.2.1 名词介绍

(1)重做日志

redo LOG:重做日志 ib_logfile0~N 48M ,轮询使用

记录的是数据页变化

redo LOG BUFFER:redo内存区域

(2)数据页存储位置

ibd : 存储数据行和索引

BUFFER pool:缓冲区池,数据页和索引页的缓冲

(3)LSN:日志序列号

磁盘数据页,redo文件,buffer pool, redo BUFFER

MYSQL 每次数据库启动,都会比较磁盘数据页和redolog的LSN,必须要求两者LSN一致数据库才能正常启动。

WAL :write ahead LOG 日志优先写的方式实现持久化。

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

CKPT : Checkpoint,检查点,就是将脏页刷写到磁盘的动作。

TXID : 事务号,InnoDB会为每一个事物生成一个事务号,伴随着整个事物。

UNDO : ibdata1,存储了事务工作过程中的回滚信息。

1.2.2 InnoDB 事务的工作流程

redo log

1》 Redo是什么?

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

2》作用是什么?

在事务ACID过程中,实现的是D持久化的作用。对于AC也有相应的作用。

3》 redo日志文件的位置

redo的日志文件:iblogfile0 iblogfile1

4》redo buffer

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

LSN:日志序列号、磁盘数据页、内存数据页、redo buffer、redolog

5》redo的刷新策略

commit;

刷新当前事务redo buffer到磁盘

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

补充:redo存储的是在事务工作过程中,数据页变化。

commit时会立即写入磁盘(默认),日志落盘成功commit。

正常MYSQL工作过程中,主要的工作是提供快速D(持久化)的功能。

 

MYSQL出现Crash异常宕机时,主要提供的是前滚功能(CSR)。 

前滚:也就是说在磁盘区域的ib_logfile里面有个数据页的文件自己有个LSN号(标记版本号),当数据库异常宕机时(异常宕机:拔掉电源,强制关闭系统,mysql磁盘更新了LSN版本号,当共享内存区域里面的redo log buffer发现数据页的LSN号比buffer pool里面高,他他就会要求buffer pool里面的数据页更新跟自己一样,然后在回写到磁盘区域)。

双一标准:

innodb_flush_at_trx_commit = 0 / 1 / 2

1:在每次事务提交时,会立即刷新redo buffer到磁盘,commit才能成功。

0:每次刷新redo buffer 到os,cache,再到fsync()到磁盘,异常宕机时,会有可能导致丢失1s内的事务。

2:每次事务提交,会立即刷新redo buffer到os,cache,再每秒fsync()磁盘,异常宕机时,会可能导致丢失1s内的事务。

目前默认是1.

除此之外:

1.redo buffer 还和操作系统缓存机制有关,所以刷写策略和innodb_flush_method参数有一定关系。

2.redo 也有group commit;简单理解就是在每次刷新已提交的redo时,顺便可以将一些未提交的事务redo也一次性刷写到磁盘。此时为了区分不同状态的redo,会加一些比较特殊的标记(是否提交标记)。

1.2.3 UNDO Logs(回滚日志)

1》 undo是什么?

undo,顾名思义"回滚日志"

作用是什么?

在事务ACID过程中,实现的是“A”原子性的作用。

另外CI也依赖于Undo

在rollback时,将数据恢复到修改之前的状态。

在CSR实现的是,先redo前滚,在undo回滚。

什么是一致性快照?

每个事务开启快照时(begin),都会通过undo

生成一个一致性的快照。

undo提供快照技术,保存事务修改之前的数据状态,保证了MVCC,隔离性,mysqldump的热备恢复机制。生成

undo在生成过程中,也会记录redo信息。

redo: 存储的是已经操作过的数据(DML(insert,update,delete))。

undo: 存储的是原始数据,可以用来恢复原始数据。

1.2.3 隔离级别和锁机制

作用:主要是提供I的特性,另外对于C的特性也有保证。

(1)transaction_isolation 事务隔离性介绍

RU:读未提交

RC: 读已提交

RR:可重复读:默认级别

SR:可串行化

读什么意思?

这里读的不是SQL层的数据行的select,而指的是存储引擎的读,是page的读取。

(2)隔离级别说明

《1》RU(READ UNCOMMITED) :读未提交

出现的问题:脏页读,不可重复读,幻读

《2》RC(READ COMMITED) :读已提交

出现的问题:不可重复读,幻读

《3》RR (REPEATABLE READ):可重复读

出现的问题:有可能出现幻读,但也可以通过其他手段防止幻读出现。

《4》SR (SERIALIZABLE) :可串行化

串行化事务。以上问题都能规避,但不利于事务的并发

(3)参数修改

mysql>SELECT @@transaction_isolation;

临时调整:

mysql>SET GLOBAL transaction_isolation='read-uncommitted';

重启会话生效

永久修改:

vim /etc/my.cnf

transaction_isolation='read-uncommited'

重启生效

 

结论:此时在session2事务中读取到了,session未提交数据的脏数据,这个现象就是脏读。

不可重复读现象

session2中的事务中,执行相同查询命令是,读到了session正在发生变化都的数据。

《1》脏读:

在session2事务读取到了,session1未提交数据的脏数据。这个现象就是脏读,对于脏读,在生产业务中是一般不允许出现的。

《2》不可重复读现象

session2中的事务中,执行相同的查询命令时读到了session1正在发生变化的数据。对于事物的隔离性和数据最终一致性要求比较高的业务,不允许出现的。

如果业务能够容忍,也是可以出现的。

《3》幻读

在一个事务窗口中,更新操作,出现了别的插入数据的幻行。

调整transaction_isolation='REPEATABLE-READ'防止不可重复读现象:

利用的就是Undo的一致性快照读。MVCC重要功能。

通过RR,已经可以解决99以上的幻读,为了更加严谨,加入GAP锁,next-lock。

GAP锁:间隙锁

GAP+ROW=next-lock。

redo把1改为2,undo把2改为1。

1.事务

1.1 ACID

Redo + UNDO + 隔离级别 + MVCC +锁

RR情况下,左边先更改保存,右边后更改保存,最终双方查看数据是怎么样的?

SESSION 1:

BEGIN; 10:00 MVCC获取10:00最新快照

UPDATE test SET num=30 WHERE num<30 ---11 15 17

COMMIT; 10:05

BEGIN; 10:05

SELECT 30 不包括

SELECT 10:06

SESSION 2;

BEGIN; 10:01 MVCC 获取10:01最新快照

INSERT INTO test VALUES (48);

commit; 10:06

BEGIN; MVCC

SELECT 30,48

前提:

1.隔离级别是事务和事务之前的特性。

2.当事务结束,隔离性就没了。

CSR

===========================

今日话题:

1.MYSQL的锁机制

1.1 介绍

相当于厕所的门。

1.2 作用

保证事物之间的隔离性

保证资源不会征用。锁是属于资源的,不是某个事务的特性。

每次事务需要资源的时候,需要申请持有资源的锁。

1.3 锁的类型

资源:

内存锁 :mutex,latch,保证内存数据页资源不被争用,不被置换。

对象锁粒度:

MDL(元数据锁):修改元数据时。DDL--->ALTER,备份

Table_lock :表锁,DDL,备份(FTWRL全局表锁),lock TABLES t1 READ,也可以升级为表锁。

record(ROW)LOCK:行锁,索引锁,锁定聚簇索引。

GAP :间隙锁,RR级别,普通辅助索引间隙锁。

NEXT-LOCK :下一级锁,GAP+record lock,普通辅助索引的范围锁。

功能分类:

I(intention)S(SHARE) : 意向共享锁,表级别

S(SHARE) : 共享锁,读锁,行级锁

I(intention)X(exclusive) :意向排他锁,表级别

X(exclusive) :排他锁,写锁,行级别

mysql> select * from sys.innodb_lock_waits\G :查看锁状态。

2. 事务得一致性ACID得C特性

A :原子性,undo,redo

D :持久性,redo(WAL)

I :隔离性,isolation level,lock,MVCC(undo)

C :保证工作前,中,后,数据的状态都是完整的,一致性。

所以C的特性是以上所有特性都是来保证一致性的。

写一致性: undo,redo,lock

读一致性: isolation level(ru,rr,rc,sr),MVCC(undo)

数据页的一致性:

double write buffer (磁盘区域)

double write buffer是Innodb在tablespace上的128个页(2个区)大小是2MB,为了解决partial page write问题,当MYSQL将脏数据flush到data file的时候,先使用memcopy将脏数据复制到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次,每次写入1MB到共享表空间,然后马上调用fsync函数,同步到磁盘上,避免缓冲带来的问题过程中,doublewrite是顺序写,开销并不大,在完成doublewrite写入后,再将double write buffer写入各表空间文件,这时是离散写入。

所以正常的情况下,MYSQL写数据PAGE时,会写两遍到磁盘上,第一遍时写到doublewrite buffer,第二遍是从doublewrite buffer写到真正的数据文件中,如果发生了极端情况(断电),Innodb再次启动后,发现了一个page数据已经损坏,那么此时就可以从doublewrite buffer中进行数据恢复。

3. 存储引擎核心参数

①innodb_flush_log_at_trx_commit=1 /0/2

②innodb_flush_method=fsync/o_direct/o_DSYNC

③innodb_buffer_pool_size

双一标准之一:redo log刷写参数

1.innodb_flush_log_at_trx_commit=1

2.innodb_flush_method=fsync/o_direct/o_DSYNC

作用:控制MYSQL刷写磁盘时,是否使用OS Cache

fsync 模式:

buffer pool的数据写到磁盘的时候,需要先经历OS cache,然后在写到磁盘。

redo buffer的数据写到磁盘的时候,需要先经历os cache,然后再写到磁盘。

O_SYNC 模式:

buffer pool的数据写到磁盘的时候

要先经历OS cache,然后在写到磁盘。

redo buffer的数据写到磁盘的时候,跨过os cache,直接写到磁盘。

O_DIRECT 模式:

buffer pool的数据写到磁盘的时候,跨过os cache,直接写到磁盘。

redo buffer的数据写到磁盘的时候,要先经历OS cache,然后在写到磁盘。

建议使用O_DIRECT,最好配合固态盘使用。

3.innodb_buffer_pool_size

OOM? ---> innodb_buffer_pool_size=80% * Total

这样设置会出现OOM(out of memory)

作用:数据缓冲区的总大小。缓冲数据页和索引页。是MYSQL最大的内存区域。

默认:128M

官方建议:80-90%内存

生产建议:75%以下,按需调配

set global innodb_buffer_pool_size=75%以下;

mysql> show engine innodb status \G 查看存储引擎状态。
共享锁(S锁):允许持锁事务读取一行。
排他锁(X锁):允许持锁事务更新或者删除一行。
意向共享锁( IS 锁):事务想要获得一张表中某几行的共享锁。
意向排他锁( IX 锁): 事务想要获得一张表中某几行的排他锁。

记录锁是最简单的行锁,仅仅锁住一行。如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE

记录锁永远都是加在索引上的。

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值