为不了解存储引擎的数据库使用者,提供了很大的便利,由于innodb适应大部分应用场景。mysql
和myisam不一样的是,innodb是一种事务型存储引擎。也就是说,innodb是支持事务的acid特性的。innodb的设计,更适合大量的小事务,而小事务大部分状况下, 均可以正常提交,不多会被回滚。git
innodb和mysiam存储数据方式不一样,innodb有本身的表空间的概念。表中的数据是存储在表空间之中的,具体存储在什么样的表空间中了,则由 innodb_file_per_table
这个参数来决定。github
ON: 为每一个innodb表创建一个空间,tablename.ibd(.ibd后缀)
sql
OFF:则会把数据存储到系统的共享表空间,ibdatax(x表明一个数字,从1开始)
数据库
在mysql5.6以前的innodb参数-innodb_file_per_table = OFF (默认),也就是数据默认会存储到系统表空间中。缓存
默认的设置会遇到下面的问题:在一个繁忙的系统中,系统表空间不断的增加。没超过咱们磁盘限制是能够接受的,可是一旦咱们磁盘空间出现不足,咱们为了释放磁盘空间,不得不在系统中删除大量无效的数据(如:长期不使用的日志类数据等)。咱们在删除数据后,系统表空间并不会缩小。这种状况下,咱们想经过复制文件的方式,对数据库进行备份。因为虽然删除了数据,但表空间大小并不会改变,这就意味着,咱们每次删除时,都要浪费很大的空间。安全
你不要觉得咱们不会遇到备份的问题,实际上,目前咱们最经常使用的热备方式,就是这样处理的。这时咱们就会遇到使用系统表空间进行存储的一些问题了。服务器
想要收缩系统表空间的惟一方法就是把系统表空间的表导出后,删除innodb的文件后,在重启mysql服务器,进行表空间的重建,而后在导入数据。这个过程实际上是很复杂的,而且十分耗时,这在业务繁忙的生产环境中了,显然是不可能作到的。架构
因此咱们若是使用系统表空间进行表数据的存储,所面临的问题是没法很容易的收缩系统文件,形成大量的空间浪费,而且会产生大量的磁盘碎片,从而下降了系统性能。并发
若是咱们使用独立表空间, 对一个大表的数据进行清理以后,能够方便的对这个表进行收缩,使用optimize table
命令 ,会对表进行重建。可是对比整个系统进行重建要快的多,并且不须要重启数据库服务器,甚至不会影响这个表的正常访问。因此从这点来看,使用独立的表空间显然要比使用系统表空间要好得多。
对于系统个表空来讲,因为只有一个文件。若是同时对多个表进行数据刷新时,实际上在文件系统层面上来讲是顺序进行的,因此会产生必定的io瓶劲。
对于独立表空间来讲,因为每一个表都有本身的表空间文件。在进行数据写入时,能够利用多个文件增长io处理的性能。因此对于平凡写入操做的系统来讲,不太适合使用系统表空间统一存放数据,而是要使用独立表空间的方式。
对使用innodb存储引擎的表使用独立表空间进行管理,在mysql5.6后,使用innodb存储引擎的默认表配置就是独立存储空间。
把原来存在于系统表空间中的表转移到独立表空间中的方法
若是数据库中使用存储过程,触发器,计划事件等,必定要记得一块儿导出。
中止mysql服务,若是是主从架构的话,咱们能够先从-从服务器上进行这些操做。中止mysql服务器以后,咱们须要修改my.cnf文件,并加入innodb_file_per_table
这个参数,而后手动删除原来innodb系统中的相关数据文件,这时后系统表空间就不含有任何数据了。
实际上,因为咱们以前已经备份了全部数据表,因此这里能够重建一个data目录,并使用mysql install db脚原本重建数据库目录
从新导入以前备份的数据,就能够完成数据的恢复,而且把原来存在于系统表空间的数据迁移到独立表空间中了。
咱们也可不按照上面操做,在修改完系统参数后,重启服务后将须要修改的全部innodb表都执行一遍:alter table table_name engine=innodb;
.这样也能够把系统表空间的表迁移到独立表空间中,可是却没法对系统表空间所占用的空间进行回收,因此仍是按照上面正规步骤吧。
咱们把系统表空间数据迁移到独立表空间后,那么如今系统表空间还有什么内容了?
答案是虽然咱们已经把系统表数据迁移了出来,可是对于系统表空间来讲,仍是有一些很重要的东西要存储的。这其中之一就是 innodb数据字典信息
数据字典是数据对象结构的元数据信息,存放与数据库对象相关的信息。如:表,列,索引,内键等内容
。
mysql是使用 .frm文件存储表结构定义的,那么.frm文件和系统空间中的数据字典又有什么区别了?
首先,.frm文件是mysql服务器层产生的文件,能够理解为mysql数据库服务器层的数据字典,这对mysql全部存储引擎都是同样的。mysql数据层所保留的东西是与存储引擎无关的,而innodb内部的数据字典是存储引擎内部产生的,并能够保证事务的一些安全性。另外,innodb存储引擎没有直接使用mysql数据上的一些类型,而是本身封装了定义,所以其数据字典存储的都是引擎相关的内容。最后,.frm文件只是简单的二进制文件,而innodb数据字典是经过b树
来进行数据管理的
除了innodb数据字典外,系统表空间还存在undo回滚段和innodb临时表
这两种在mysql5.7都是能够从系统表移除的 了,但还会有不少人默认的把他们存储在系统表空间中。这里要声明的是,undo回滚段的存储在mysql5.6就已经支持了。
彻底支持事物的acid特性
redo log 和 undo log
redo log实现事物的持久性,其有两部分组成
innodb_log_buffer_size:配置redo log缓冲区的大小,以字节为单位,程序每隔秒就会把缓存区数据刷新到磁盘里,因此这个缓存区不用配置太大。
innodb_log_files_in_group:决定了数据库目录下的ib_**的文件数量
undo log 帮助对未提交事物进行回滚和实现多版本并发控制
联系
同myisam支持的表级锁是不同的,行级锁的特色是在进行写操做时,咱们所须要锁定的资源更少,这样能够支持的并发就更多。须要注意的是,innodb的行级锁是由存储引擎层实现的,mysql服务器彻底不了解存储引擎中锁的实现方式。
说到锁可能你们还不太了解,数据库中锁的做用是什么了?由于锁对咱们数据库的性能有很是大的影响,因此这里介绍下什么是锁。
可能不少开发人员会问,常常听到dba说的各类各样的锁,好比说行级锁,表级锁,共享锁,专断锁等等。这些锁的做用是啥了?
锁是数据库系统区别于文件系统的重要特性锁的主要做用是管理共享资源的并发访问
。并发访问是一个很让人头疼的事情啊,对于任何一个在窜行环境下工做良好的系统,一旦涉及到并发的状况就有可能出现各类各样的问题。
好比说邮件系统,在一个邮箱中,全部的邮件都是窜行的叠在一块儿的,彼此首尾相连。这种结构对于读取和投递邮件都是有很大的好处的。当有新的邮件到来时,只要插入文件末尾就能够了。当有两个用户,同时对邮箱进行邮件投递,那会出现什么样的状况了?颇有可能邮箱的数据会被破坏,两封性的内容会交叉在一块儿。固然了,这可能和咱们日常生活的感觉有很大的不一样。那是由于如今的邮箱系统都是利用了锁进行了控制。锁保证了一个用户向邮箱投递邮件时,另外一个用户会阻塞,没法向相同的文件末尾写入文件。
那么锁的另外一个做用就是实现事务的隔离性
。前面提到过,咱们经过redo log 和 undo log 实现了事务的原子性,一致性和持久性,而隔离性就须要锁来实现。对于未提交的事务锁定的数据是没法被其余事务查询到的。
了解了什么是锁,及锁的做用后,咱们来看看锁的常见分类。
共享锁(也称读锁):能够看出读锁是共享的,不会被阻塞的, 多个线程能够在同一时间读取同一资源,而不相互干扰。
独占锁(也称写锁):写锁是独占的,是排它的,会阻塞其余的写锁和读锁。这是对数据完整性的考虑,只有这样才能保证在给定的时间里,只有一个线程能够执行写入,并防止其余用户正在读取写入的资源,也就是咱们前面说的事务的隔离性。
对于innodb来讲,读锁和写锁都是行锁。兼容性指的是对同一行记录可见兼容的状况
按照上面介绍,对于同一资源的请求应该是互斥的,可是实际体验并不和以上相同。(锁比上面提到的复杂多了)
初始化数据库中数据
测试,两个链接启动一个事务。一个链接给表的第一行记录加个独占锁,不提交事务
另外一个链接获取加了独占锁的数据,仍然能够获取到
这和咱们介绍的兼容性状况彻底不一样,这是为何了?
这就是innodb在实现锁上的独到之处,这里innodb用到了咱们上面提到的undo log中的记录,因此咱们在第二个链接中查看的数据其实是存储在undo log中的版本。也就是说,并非咱们在第一个链接中进行更新的。
锁的粒度就是锁的策略,指被加锁资源的最小单位
。好比在行上加锁,那么最小单位就是行,这锁就称为行级锁。若是说的最小单位是列,那就称为锁的列级锁。同理,若是锁的最小单位是表的话,那么锁的最小单位就是表级锁。
表级锁:mysql中最基本的表策略,开销最小的策略,并发性低。表锁会在加锁时锁定整张表,一个用户在对表进行写操做前,须要先得到写锁。这会阻塞其余用户的读写操做,只有没有写锁时,其余用户才能够获取读锁,读锁以前说了是相互间不会阻塞的。表级锁一般是在mysql服务器层实现的,因此虽然innodb实现了行级锁,可是在一些时候,mysql数据服务层仍是会对innodb表加上表级锁。
实验使用两个链接,一个链接加表级独占锁
第二个链接从表获取数据
第一个链接执行解锁操做,第二个链接就会被执行
行级锁:能够最大程度的支持并发处理,同时锁的开销比表级锁要大。目前innodb和其余的存储引擎中实现了行级锁,行级锁只在存储引擎中进行实现,而mysql服务层并无实现。
什么是阻塞:阻塞是不一样锁之间兼容性的关系。在有些时刻,一个事务中的锁须要等待另外一事务中的锁释放它所占用的资源,这就造成了阻塞。阻塞是为了确保事务能够并发且正常的运行, 可是,当一个系统中若是出现了大量的阻塞,每每就意味着系统中存在着问题。也许是在一个被频繁更新的表上出现了慢查询或是因为其余的管理操做,如表备份等。对一个频繁访问的资源加上了排他锁,过多的阻塞不是个好的现象,使数据库中的链接大量的堆积,占用大量的系统资源,使得系统的整体性能降低。
什么是死锁:死锁是指两个或两个以上的事务,在执行过程当中相互占用了对方等待的资源 ,而产生的一种异常。处在阻塞中的事务占有被阻塞事务的多个资源,而死锁是产生事务的多个事务之间相互占用对方等待的资源,这就是阻塞和死锁最大的不一样之处。另一点不一样是,死锁数据库系统会自动发现,而且在多个资源占用的事务中,选择一个资源占用最少的事务来进行回滚操做。这样就可使其余事务正常的运行了,因此说死锁是能够由系统自动处理的。若是只是有少许的死锁,并不会对系统形成什么影响。只要在应用程序中,发现死锁,并进行从新处理就能够了。可是,若是一个系统中频繁的出现大量的死锁,这时就须要留意了。一般状况下,死锁能够经过在多个事务中按相同的顺序访问所须要的资源来解决,也可经过增长相关的索引来解决。
show engine innodb status 这命令的用法百度
innodb适合于大多数OLTP应用。不管是否须要事务支持,只要是不使用innodb所不支持的特殊的功能的话,咱们都应该在新的系统中使用innodb存储引擎。其中所说的特殊功能可能就包括以前介绍myisam功能中对于空间应用和全文索引这些应用。因为在mysql5.7以前,只支持myisam存储引擎,因此若是咱们要使用mysql来存储这类应用数据的话,可能就只能选择myisam存储引擎了。但是这种状况在mysql5.7以后有了改变,innodb支持全文索引和空间函数了
。 因此对于这类应用,咱们也能够彻底使用innodb存储引擎来进行存储了。innodb和myisam是mysql最经常使用的两种存储引擎,还有一些引擎会使用到,请听下回分解。
InnoDB 引擎独立表空间 innodb_file_per_table
MySQL Server参数优化 - innodb_file_per_table(独立表空间)
show engine innodb status解读
死锁和阻塞的关系