Innodb存储引擎的特性(1).

现在关于系统表空间和独立表空间还有一个问题,也要说明一下,我们把数据迁移到独立表空间后,

那么现在的系统表空间中呢,还有什么内容呢,答案是我们虽然已经把表的数据从系统表空间中迁移出来,

但是对于系统表空间来说,还是有一个很重要的东西要清除的,其中之一呢,就是Innodb的数据字典,数据字典是

数据库对象结构的源数据信息,当存放与数据库对象相关的一些信息,表,列,索引,外键等这些内容,细心的朋友可能

已经发现了,我之前说过,MYSQL是使用frm文件来存储表结构定义的,那么frm文件和系统表空间中,存放的数据字典之间

有什么区别呢,首先来说,frm文件是MYSQL服务器产生的文件,可以理解为MYSQL数据库层的数据字典,这个对于MYSQL的

所有存储引擎呢,一样的,大家如果还记得话,我在介绍MYSQL数据库架构的时候说过,在MYSQL服务器层,所保存的东西是

与存储引擎无关的,而Innodb内部的数据字典呢,是存储引擎内部产生的,并可以保证事务的安全性,另外innodb存储引擎呢,

没有直接使用MYSQL数据库上的,一些上传的类型,而是自己封装了一些定义,因此,数据字典存储的都是引擎相关的一些内容,

最后,frm只是一个简单的二进制文件,而innodb数据字典呢,是通过B树进行管理的,除了innodb数据字典以外,在系统表空间,

还会存在undo回滚段和innodb临时表,虽然这两种数据呢,在MYSQL5.7版本中,都是可以从系统表空间中移出的,但是还是有很多

会默认在表空间中,对于Undo字段的在MYSQL5.6时就已经支持了,这里讲了Innodb存储上的一些特点,下面来看一下其他的一些特色

存储引擎的其他特色,首先Innodb是一种事务性的存储引擎,其完全支持事务的ACID特性,也就是原子性,一致性,隔离性,

持久性,关于事务的这四个特性呢,之前已经介绍过了,这里就不过多介绍了,我们在这里主要介绍一下,Innodb是如何实现

这几个特性的,为了实现事务的原子性呢,一致性和持久性,Innodb使用了两个特殊的日志类型,也就是重构日志,Redo log,

和回滚日志 undo log,这两个日志的作用是完全不同的,Redo Log主要是用于实现事务的永久性,其由两部分组成,一个是内存

中的重做日志缓存区,由Innodb参数来决定大小,另一个是日志文件,我们在文件系统中看到的,我们可以在系统中来看一下这

两个配置

首先我们要进入到我们的系统,我们可以使用show命令来看一下,系统中的关于我们刚才所说的,两个参数的配置情况,

其中一个是innodb_log_buffer_size

show variables like 'innodb_log_buffer_size';

这个就是我们目前MYSQL中所配备的redo log缓冲区的大小,这个数值是以字节为单位的,由于我们最多每隔一秒

把缓冲区刷新到磁盘上,所以这缓冲区呢不用配置的太大,另外一个呢,我们在文件系统中查看,我们可以在数据库目录下

看到,ib_logfile来开头的一些文件,这个文件的数量呢,是由innodb_log_file来决定的,这里我们看到有两个ib_logfile

的文件,一个是ib_logfile0,一个是ib_logfile1

就是参数,我们刚才所提到的参数,innodb_log_files_in_group,所以会产生两个innodb文件

show variables like 'innod_log_file_in_group';

undo log的主要作用是,用于帮助未提交事务进行回滚,和实现那个mvcc,多版本并发控制的,Redo log中存储的是

已提交的事务,而undo log中呢,存储的是未提交的事务,因此当我们对innodb表中的数据,进行修改时,也会产生redo log,

还会产生一定的undo log,这样如果用户执行的语句由于某种原因失败使用rollback语句进行回滚时,就需要利用undo log

中的信息了,由上面的介绍可知,redo log基本是顺序写入的,在数据库运行时,不需要对redo log进行读取,而undo log呢,

且需要随机的读写的,前面说过,MYSQL5.6版本的undo log呢可以独立于系统表空间而存在,如果条件允许,我们就可以把undo

log存储在固态存储上,比如SSD和PCI-E设备上,这样可以获得更好的性能,Innodb第二个特性是,Innodb所支持的是行级锁,而

这一点呢,同MYISAM引擎所支持的表级锁呢,是不一样的,行级锁的特点呢,在进行写操作时呢,我们需要锁定的资源呢,更少,

这样呢所能支持的并发呢更多,这里所需要注意的是,行级锁是在存储引擎层实现的,MYSQL服务器呢,完全不了解存储引擎中,

锁的实现方式,说到锁,可能大家还不是太了解,锁的作用是什么呢,因为锁对于数据库的性能又非常大的影响,所以我觉得有必要

在这里给大家简单的介绍一下,什么是锁,可能很多开发人员呢会问,经常听到DBA说到各种各样的锁,比如说行级锁啊,表级锁啊,

共享锁,那么这些锁的作用又是什么呢

首先我们来看一下什么是锁,锁是数据库系统区别于文件系统的一个重要特性,作用是管理共享资源的并发访问,

并发访问是一个让人很头疼的问题了,对于任何的串行环境下,良好的系统,一旦涉及到并发的情况下,可能会出现各种各样的

问题,在这里我们可以举一个很常见的邮件系统的列子,来说明锁的作用,我们知道一个邮箱中,所有的邮件是串行连接在一起的,

于此首尾相连,这种结构呢,对于读取邮件呢,都是有很大的好处的,当有新的邮件到来时呢,只要插入到文件末尾就可以了,那我们

想象一下,这时如果有两个用户同一个邮件进行邮件投递,会出现什么样的情况呢,很有可能,邮箱的数据会被破坏,两封信件的内容

会交叉在一起,当然了,这可能跟我们平常生活中感受可能有很大的不同,那是因为现在的邮件系统,都是通过锁,对这种情况进行的

控制,所保证了在一个用户向这邮件投递邮件时,另一个用户会阻塞,无法向相同的邮件末尾写入邮件,那么锁的另一个作用呢,需要事务

的隔离性,前面提到过,通过redo log和undo log实现了事务的原子性,一致性和持久性,而隔离性是需要锁来实现的,对于未提交的

事务,锁定的事务是无法被其他的事务所查询到的

了解了什么是锁,以及锁的作用后,我们来看一看锁的常见分类,其实锁最主要的类型只有两种,共享锁也称之为读锁,

和独占锁也称之为写锁,从名字中我们也可以看出来,读锁是共享的,也就是说,相互之间不会阻塞的,多个线程可以在

同一个时间读取同一资源,而不相互干扰,写锁是独占的,可以说是排他的,也就是说,一个写锁会阻塞其他的写锁或读锁,

这是出于数据完整性的考虑,只有这样才能保证在给定的时间里,就一个线程能执行写入,并防止其他用户读取正在写入的

同一资源,也就是前面我们说的事务的隔离性,我们看一下旁边的表给出了读写锁的兼容关系,从表中我们可以看出,写锁也

就是独占锁,和所有的其他锁是不兼容的,而读锁和读锁之间是兼容的,需要注意的是,以Innodb来说,读锁和写锁呢,都是

行锁,兼容性是指的同一行记录,兼容性的情况,当然Innodb的锁呢,实际上呢,要比这个复杂的多,如果按照我们上面介绍的,

大家可能会发现,对于同一资源的读写请求呢,应该是互斥的,但是我们实际体验呢,可能并不和以下的情况相同,我们可以通过

以下的实验来看一下

就以我们刚才建的myinnodb来测试,我们现在回顾一下这个表的结构,其实这个表的结构是相当简单的,

只有两列数据,分别是id和c1,我们可以往这个表中插入一些数据

再来看一下这个表的内容,我们先插入一些数据,为了下面演示方便呢,我们来看,我们来看一下表的内容

insert into myinnodb values(2,'bb'),(3,'cc');

select * from myinnodb;

这个表一共有两行数据,一个是id为2,一个是id为3,现在我们就可以开始我们的测试了,测试需要两个连接来请求两个事务,

在一个连接中呢,我们启动一个事务,并在第一个表的记录加一个独占锁,这里启动一个事务就是begin,这里我们就启动了一个

事务,我们来给这个把表的第一行加一个独占锁,set c1='bbb',条件id等于2的,我们id等于2的加了一个独占锁

begin;

update myinnodb set c1='bbb' where id = 2;

我们对他不可以提交,我们来看一下相同行数据的情况,id等于2

select * from myinnodb where id = 2;

我们看到的还是更新之前的数据,那么问题出现了,大家可以看到,在连接2中查询呢,并没有被连接1上的

独占锁给阻塞,这和我们上面的兼容性情况完全不同,这是为什么呢,这是innodb实现锁的独到之处,Innodb

用到了我们上面提到的undo log记录,所以呢,我们在第二个连接中查看的数据呢,实际上是存在undo log中的

版本,并不是我们在第一个连接中所更新的,他看到的还是老的数据版本,所以innodb在实现锁上还是相当复杂的,

其实在innodb中呢,还存在异向共享锁和异向独占锁两种锁,这是为了在不同力度上进行加锁而设计的,下面我们

来看看锁的粒度是什么,熟悉数据仓库的朋友呢,可能对粒度的含义很清楚了,所谓锁的粒度呢,实际上也是锁的策略,

就是被加锁的最小单位,比如在行上加锁,那么最小单位就是行,这种锁就称之为行级锁,如果的锁的最小单位是页,

那么这个锁也称之为页级锁,同理,如果最小单位是表的话,这个锁的粒度是表级锁,这种提高并发的方式呢,让锁定义的

对象尽可能的小,最理想的方式呢,只需要对需要修改的数据进行精确的锁定,任何时候在给定的资源上,锁定的数据越小,

数据的并发性能也就越高,只要相互之间不产生阻塞,就可以了,我们来看一下MYSQL的两种锁的粒度,首先第一种呢是表级

锁,就是MYSQL中,最基本的锁策略,也是开销最小的策略,开销小呢,意味着并发性就会低,表锁会在加锁时呢,锁定整张表,

一个用户在对表进行写操作前,需要获得写锁,就会阻塞其他用户读写操作,只有没有写锁时呢,他读取的用户呢,才能获得锁,

读锁之前说了,相互间是不会阻塞的,表级锁呢通常是在MYSQL服务器上所实现的,所以虽然Innodb实现了行级锁,但是在一些时候,

MYSQL数据服务层呢,还是会对Innodb加上表级锁,比如我们在做alter table操作时,为了让大家更直观的了解MYSQL中表级锁,

还是通过实验来让大家看一下表的效果,还是用之前的myinnodb这张表吧,大家知道这张表呢是innodb存储引擎的表这里呢可以

来看一下,我们把刚才的事务呢rollback掉

rollback;

这个时候我们再来看一下这张表的定义

show create table myinnodb;

这张表呢是一张innodb存储引擎的表,默认是在表上加行级锁的,我们怎么让这张表加表级锁呢,

其实很简单,这个实验我们同样需要两个连接,在第一个连接上我们只需要执行下面这个命令,

lock table myinnodb write;

这样就给myinnodb加上一个表级的独占锁

我们在第二个连接上进行上面的查询,我们看会怎么样

select * from myinnodb;

大家可以看到,这个时候这个操作就被阻塞了

知道在第一个连接上执行解锁操作时,那么第二个连接上的查询才会被执行

unlock tables;

MYSQL常见的粒度呢就是行级锁,行级锁可以最大程度的支持并发处理,当然锁的开销要比表级锁要大,

目前innodb和其他的存储引擎已经实现了行级锁,行级锁是在存储引擎中进行实现,而MYSQL服务器并没有实现,

关于行级锁我们之前已经介绍了很多了,所以就不再多说了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值