精华内容
下载资源
问答
  • Mysql InnoDB底层实现

    2020-10-23 00:34:48
    Mysql InnoDB底层实现1.InnoDB存储结构2.InnoDB的索引实现3.InnoDB中的八种锁3.1 共享锁或排它锁(Shared and Exclusive Locks)3.2 意向锁(Intention Locks)3.3 索引记录锁(Record Locks)3.4 间隙锁(Gap Locks)3.5 下...

    1.InnoDB存储结构

    InnoDB的基本存储结构是页,页也是InnoDB存储引擎管理数据库的最小磁盘单位。在这里插入图片描述

    • 各个数据页之间是一个双向链表
    • 每个数据页中的记录则是一个单向链表
    • 通过主键查找可以在数据页的页目录中通过二分查找,快速找到指定记录,而以其他列作为搜索条件时则需要依次遍历单链表中的每条记录

    2.InnoDB的索引实现

    因此,我们需要将无序的数据变得相对有序,以加快查询速度,这就是索引的作用。

    InnoDB 是通过 B+Tree 结构对主键建立索引,然后在叶子节点中存储记录,该索引被称作聚集索引。采用 InnoDB 引擎的数据存储文件有两个,一个定义文件,一个是数据文件。

    若建索引的字段不是主键 ID,则对该字段建索引,然后在叶子节点中存储的是该记录的主键,然后通过主键索引找到对应的记录,该索引被称作非聚集索引。在这里插入图片描述

    3.InnoDB中的八种锁

    InnoDB一共有8种锁类型,其中,意向锁(Intention Locks)和自增锁(AUTO-INC Locks)是表级锁,剩余全部都是行级锁。此外,共享锁或排它锁(Shared and Exclusive Locks)尽管也作为8种锁类型之一,它却并不是具体的锁,它是锁的模式,用来“修饰”其他各种类型的锁。

    3.1 共享锁或排它锁(Shared and Exclusive Locks)

    它并不是一种锁的类型,而是其他各种锁的模式,每种锁都有shard或exclusive两种模式。

    当我们说到共享锁(S锁)或排它锁(X锁)时,一般是指行上的共享锁或者行上的排它锁。需要注意的是,表锁也存在共享锁和排它锁,即表上的S锁和表上的X锁,表上的锁除了这两种之外,还包括下面将会提到的意向共享锁(Shard Intention Locks)即IS锁、意向排它锁(Exclusive Intention Locks)即IX锁。表上的锁,除了这四种之外,还有其他类型的锁,这些锁都是在访问表的元信息时会用到的(create table/alter table/drop table等)

    S锁允许一个事务读取一行,多个用户可以同时读取同一个资源,但是阻止其他事务获得相同数据集的X锁,也就是不允许修改。

    X锁会允许获得排他锁的事务更新数据,但是阻止其他事务取得相同数据集的S锁和X锁,也就是说X锁会阻塞其他的写锁和读锁。

    举例:

    情景一:假设T1持有数据行r上的S锁,则当T2请求r上的锁时:
    
    1. T2请求r上的S锁,则,T2立即获得S锁。T1和T2同时都持有r上的S锁。
    
    2. T2请求r上的X锁,则,T2无法获得X锁。T2必须要等待直到T1释放r上的S锁。
    
    
    情景二:假设T1持有r上的X锁,则当T2请求r上的锁时:
    
    T2请求r上的任何类型的锁时,T2都无法获得锁,此时,T2必须要等待直到T1释放r上的X锁。
    

    3.2 意向锁(Intention Locks)

    为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB有两种内部使用的意向锁,有shard或exclusive两种模式,这两种意向锁都是表锁。

    意向锁的目的是告知其他事务,某事务已经锁定了或即将锁定某个/些数据行。事务在获取行锁之前,首先要获取到意向锁,即:

    1. 事务在获取行上的S锁之前,事务必须首先获取 表上的 IS锁或表上的更强的锁。

    2. 事务在获取行上的X锁之前,事务必须首先获取 表上的 IX锁。

    事务请求锁时,如果所请求的锁 与 已存在的锁兼容,则该事务 可以成功获得 所请求的锁;如果所请求的锁 与 已存在的锁冲突,则该事务 无法获得 所请求的锁。

    意向锁IS和IX和任何行锁都兼容,它实际上只会阻塞全表请求
    

    3.3 索引记录锁(Record Locks)

    也就是所谓的行锁,锁定的是索引记录。索引记录锁总是锁定索引记录,即使表上并未定义索引。表未定义索引时,InnoDB自动创建隐藏的聚集索引(索引名字是GEN_CLUST_INDEX),使用该索引执行record lock。

    3.4 间隙锁(Gap Locks)

    索引记录之间的间隙上的锁,锁定尚未存在的记录,即索引记录之间的间隙。有shard或exclusive两种模式,但,两种模式没有任何区别,二者等价。

    gap lock锁住的间隙可以是第一个索引记录前面的间隙,或相邻两条索引记录之间的间隙,或最后一个索引记录后面的间隙。

    InnoDB索引是B+树形式的,因此索引是从小到大按序排列的,在索引记录上查找给定记录时,InnoDB会在第一个不满足查询条件的记录上加gap lock,防止新的满足条件的记录插入。

    gap lock存在的唯一目的就是阻止其他事务向gap中插入数据行,它用于在隔离级别为RR时,阻止幻影行(phantom row)的产生;隔离级别为RC时,搜索和索引扫描时,gap lock是被禁用的,只在 外键约束检查 和 重复key检查时gap lock才有效,正是因为此,RC时会有幻影行问题。

    gap lock是RR(可重复读)和RC(读已提交)隔离级别的一个重要区别
    

    3.5 下一个键锁(Next-Key Locks)

    next-key lock 是 (索引记录上的索引记录锁) + (该索引记录前面的间隙上的锁) 二者的合体,它锁定索引记录以及该索引记录前面的间隙。有shard或exclusive两种模式。

    当InnoDB 搜索或扫描索引时,InnoDB在它遇到的索引记录上所设置的锁就是next-key lock,它会锁定索引记录本身以及该索引记录前面的gap。

    3.6 插入意向锁(Insert Intention Locks)

    一种特殊的gap lock。INSERT操作插入成功后,会在新插入的行上设置index record lock,但,在插入行之前,INSERT操作会首先在索引记录之间的间隙上设置insert intention lock,该锁的范围是(插入值, 向下的一个索引值)。有shard或exclusive两种模式,但,两种模式没有任何区别,二者等价。、

    insert intention lock发出按此方式进行插入的意图:多个事务向同一个index gap并发进行插入时,多个事务无需相互等待。
    

    3.7 自增锁(AUTO-INC Locks)

    自增锁也是表锁,在向带有AUTO_INCREMENT列 的表时插入数据行时,事务需要首先获取到该表的AUTO-INC表级锁,以便可以生成连续的自增值。插入语句开始时请求该锁,插入语句结束后释放该锁(注意:是语句结束后,而不是事务结束后)。

    3.8 空间索引(Predicate Locks for Spatial Indexes)

    这个锁使用较为稀少,可以查看mysql技术文档自行拓展

    https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-predicate-locks

    展开全文
  • 浅析Innodb事务底层实现原理

    千次阅读 2019-07-11 16:42:57
    MySQL只有innodb引擎支持事务,因此这篇文章也是以innodb为背景写的。 一、事务并发会带来什么问题? 脏读:读到了其他事务未提交的数据 不可重复读:当前事务先进行了一次数据读取,然后再次读取到的数据是别的...

    如果对事务的基本知识不是太了解,可以先去看这篇文章【MySQL】事务知识小结

    MySQL只有innodb引擎支持事务,因此这篇文章也是以innodb为背景写的。

    一、事务并发会带来什么问题?

    • 脏读:读到了其他事务未提交的数据
    • 不可重复读:当前事务先进行了一次数据读取,然后再次读取到的数据是别的事务修改成功的数据,导致两次读取到的数据不一致(update、delete)
    • 幻读:当前事务读第一次取到的数据比后来读取到数据条目少(insert)

    解决上面的问题就需要设置相应的事务隔离性

    • Read Uncommitted(未提交读) :事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。
    • READ COMMITTED (提交读):保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。
    • REPEATABLE READ(重复读) :默认隔离级别,保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但不能避免“幻读”,但是带来了更多的性能损失。
    • Serializable (串行化):最严格的级别,事务串行执行,资源消耗最大,解决了所有问题。

    需要注意,在innoDB引擎中,当隔离级别为可重复读就可以解决幻读的情况,因为innodb

    • 在快照读读情况下,mysql通过mvcc来避免幻读。
    • 在当前读读情况下,mysql通过next-key来避免幻读

    因此innodb的默认隔离级别就是可重复度.

    二、如何实现事务隔离级别?

    首先有两种方式:

    • 加锁:在读取数据前,对其加锁,防止其他事务对数据进行修改。
    • MVCC:多版本并发控制,指的是一种提高并发的技术,生成一个数据请求时间点的一致性数据快照,并用这个快照来提供一定级别的一致性读取.

    最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。在内部实现中,InnoDB是在undolog中实现的,通过undolog可以找回数据的历史版本。

    三、锁内容详解

    1、锁的分类

    1.1表锁和行锁

    首先来看看表锁和行锁,顾名思义,表锁是锁住整张表,行锁是锁住一行的数据,下面是它们的区别

    • 锁定粒度:表锁>行锁
    • 加锁效率:表锁>行锁
    • 冲突概率:表锁>行锁
    • 并发性能:表锁<行锁

    MyISAM存储引擎仅支持表锁;innodb存储引擎既支持行锁又支持表锁。

    1.2共享锁和排他锁(行锁)

    共享锁:又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同意数据可以共享一把锁,都能访问到数据,但是只能读不能修改。

    共享锁的加锁释放锁方式:

    BEGIN;
    
    select * from student where id =1 LOCK INSHARE MODE;
    
    commit/rollback;

    排他锁:又称为写锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事物就不能再获取该行的锁,只有该获取了排他锁的事务才能对数据进行读取和修改。

    排他锁的加锁释放锁方式:

    • 自动:delete/update/insert 默认加上排他锁
    • 手动:select * from student where id = 1 FOR UPDATE;

    1.3意向共享锁和意向排他锁(表锁)

    首先需要知道意向锁是由数据引擎自己维护的,用户无法手动操作意向锁。

    意向共享锁:表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的意向共享锁。

    意向排他锁:表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的意向排他锁。

    思考:为什么需要(表级别的)意向锁?

    因为在加表锁时,如果此时表中已经有其他事务锁定了这张表的任一行,表锁就不能成功,因此在加表锁时会先去判断每一行有没有加锁,然后再看加不加表锁,但是判断每一行加没加锁显然效率太低了,因此就需要意向锁,使用意向锁就会在加表锁时直接判断是否有意向锁即可,提高了效率。

    2、锁的作用

    锁是为了解决资源竞争并发的问题,在Java中资源就是对象,在Mysql中就是数据表、数据行

    3、锁到底锁住了什么?

    当数据库中没有索引时,加锁会锁住整张表.

    其实数据库中的锁是锁住索引项实现的!对于innodb而言,如果没有索引它定义一个主键来作为聚簇索引。那也就是在我们没有创建索引时,对innodb存储引擎而言,我们加锁表中的数据,锁住的就是这个隐式聚簇索引,InnoDB行锁对唯一索引或主键索引的数据生效,若我们没有手动的去加索引,那么对于加锁时只有sql语句能用到默认的聚簇索引也就是默认的主键索引时才会锁住行,因此我们常说如果没有建主键索引,使用innodb时会锁整张表。

    4、行锁的算法

    分为三种:记录锁、间隙锁、临键锁

    记录锁:总是会锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。

    间隙锁: 只在RR级别存在,是为了解决Phantom Problem(幻象/幻读),利用这种锁技术,锁定的不是单个值,而是一个范围。

    临键锁: 是结合了记录锁和间隙锁的一种锁定算法,在此种算法下,InnoDB对于行的查询都是采用这种锁定算法。

     

    在mysql中就是使用锁+MVCC实现事务,当只有写写时才会阻塞。

    展开全文
  • 了解InnoDB底层原理

    2020-12-19 23:04:22
    存储引擎,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。 有哪些已有的存储引擎可以让我们选择呢? InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated、...

    存储引擎 

    存储引擎,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。

     

    有哪些已有的存储引擎可以让我们选择呢?

    InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated、Example

     常用的存储引擎目前就只有InnoDB和MyISAM。

    InnoDB是目前使用最广的MySQL存储引擎,MySQL从5.5版本开始InnoDB就已经是默认的存储引擎了。

    InnoDB的内存架构主要分为三大块,缓冲池(Buffer Pool)、重做缓冲池(Redo Log Buffer)和额外内存池 


     缓冲池

    InnoDB为了做数据的持久化,会将数据存储到磁盘上。但是面对大量的请求时,CPU的处理速度和磁盘的IO速度之间差距太大,为了提高整体的效率, InnoDB引入了缓冲池

    当有请求来查询数据时,如果缓存池中没有,就会去磁盘中查找,将匹配到的数据放入缓存池中。同样的,如果有请求来修改数据,MySQL并不会直接去修改磁盘,而是会修改已经在缓冲池的页中的数据,然后再将数据刷回磁盘,这就是缓冲池的作用,加速读,加速写,减少与磁盘的IO交互。

    缓冲池说白了就是把磁盘中的数据丢到内存,那既然是内存就会存在没有内存空间可以分配的情况。所以缓冲池采用了LRU算法,在缓冲池中没有空闲的页时,来进行页的淘汰。但是采用这种算法会带来一个问题叫做缓冲池污染

    当你在进行批量扫描甚至全表扫描时,可能会将缓冲池中的热点页全部替换出去。这样以来可能会导致MySQL的性能断崖式下降。所以InnoDB对LRU做了一些优化,规避了这个问题。

    MySQL采用日志先行,在真正写数据之前,会首先记录一个日志,叫Redo Log,会定期的使用CheckPoint技术将新的Redo Log刷入磁盘

    除了数据之外,里面还存储了索引页、Undo页、插入缓冲、自适应哈希索引、InnoDB锁信息和数据字典。下面选几个比较重要的来简单聊一聊。


    插入缓冲

     

    插入缓冲针对的操作是更新或者插入,我们考虑最坏的情况,那就是需要更新的数据都不在缓冲池中。那么此时会有下面两种方案。

    1. 来一条数据就直接写入磁盘
    2. 等数据达到某个阈值(例如50条)才批量的写入磁盘

    很明显,第二种方案要好一点,减少了与磁盘IO的交互。

     


    两次写

    插入缓冲提高了MySQL的性能,而两次写则在此基础上提高了数据的可靠性。我们知道,当数据还在缓冲池中的时候,当机器宕机了,发生了写失效,有Redo Log来进行恢复。但是如果是在从缓冲池中将数据刷回磁盘的时候宕机了呢?

    这种情况叫做部分写失效,此时重做日志就无法解决问题

     在刷脏页时,并不是直接刷入磁盘,而是copy到内存中的Doublewrite Buffer中,然后再拷贝至磁盘共享表空间(你可以就理解为磁盘)中,每次写入1M,等copy完成后,再将Doublewrite Buffer中的页写入磁盘文件。

    有了两次写机制,即使在刷脏页时宕机了,在实例恢复的时候也可以从共享表空间中找到Doublewrite Buffer的页副本,直接将其覆盖原来的数据页即可。


    自适应哈希索引

     

    自适应索引就跟JVM在运行过程中,会动态的把某些热点代码编译成Machine Code一样,InnoDB会监控对所有索引的查询,对热点访问的页建立哈希索引,以此来提升访问速度。

    你可能多次看到了一个关键字


    ,是InnoDB中数据管理的最小单位。当我们查询数据时,其是以页为单位,将磁盘中的数据加载到缓冲池中的。同理,更新数据也是以页为单位,将我们对数据的修改刷回磁盘。每页的默认大小为16k,每页中包含了若干行的数据,页的结构如下图所示。

     

     

    我们只需要知道这样设计的好处在哪儿。每一页的数据,可以通过FileHeader中的上一下和下一页的数据,页与页之间可以形成双向链表。因为在实际的物理存储上,数据并不是连续存储的。你可以把他理解成G1的Region在内存中的分布。

    而一页中所包含的行数据,行与行之间则形成了单向链表。我们存入的行数据最终会到User Records中,当然最初User Records并不占据任何存储空间。随着我们存入的数据越来越多,User Records会越来越大,Free Space的空间会越来越小,直到被占用完,就会申请新的数据页。

    User Records中的数据,是按照主键id来进行排序的,当我们按照主键来进行查找时,会沿着这个单向链表一直往后找,


    重做日志缓冲

    InnoDB中缓冲池中的页数据更新会先于磁盘数据更新的,InnoDB也会采用日志先行(Write Ahead Log)策略来刷新数据,什么意思呢?当事务开始时,会先记录Redo Log到Redo Log Buffer中,然后再更新缓冲池页数据。

    Redo Log Buffer中的数据会按照一定的频率写到重做日志中去。被更改过的页就会被标记成脏页,InnoDB会根据CheckPoint机制来将脏页刷到磁盘。


    日志 

    日志分为如下两个维度。

    1. MySQL层面
    2. InnoDB层面

    MySQL日志

     

    MySQL的日志可以分为错误日志、二进制文件、查询日志和满查询日志。

    • 错误日志 很好理解,就是服务运行过程中发生的严重错误日志。当我们的数据库无法启动时,就可以来这里看看具体不能启动的原因是什么
    • 二进制文件 它有另外一个名字你应该熟悉,叫Binlog,其记录了对数据库所有的更改。
    • 查询日志 记录了来自客户端的所有语句
    • 慢查询日志 这里记录了所有响应时间超过阈值的SQL语句,这个阈值我们可以自己设置,参数为long_query_time,其默认值为10s,且默认是关闭的状态,需要手动的打开

     


    InnoDB日志 

    InnoDB日志就只有两种,Redo Log和Undo Log

    • Redo Log 重做日志,用于记录事务操作的变化,且记录的是修改之后的值。不管事务是否提交都会记录下来。例如在更新数据时,会先将更新的记录写到Redo Log中,再更新缓存中页中的数据。然后按照设置的更新策略,将内存中的数据刷回磁盘。
    • Undo Log 记录的是记录的事务开始之前的一个版本,可用于事务失败之后发生的回滚。

    Redo Log记录的是具体某个数据页上的修改,只能在当前Server使用,而Binlog可以理解为可以给其他类型的存储引擎使用。这也是Binlog的一个重要作用,那就是主从复制,另外一个作用是数据恢复

    上面提到过,Binlog中记录了所有对数据库的修改,其记录日志有三种格式。分别是Statement、Row和MixedLevel。

    • Statement 记录所有会修改数据的SQL,其只会记录SQL,并不需要记录下这个SQL影响的所有行,减少了日志量,提高了性能。但是由于只是记录执行语句,不能保证在Slave节点上能够正确执行,所以还需要额外的记录一些上下文信息
    • Row 只保存被修改的记录,与Statement只记录执行SQL来比较,Row会产生大量的日志。但是Row不用记录上下文信息了,只需要关注被改成啥样就行。
    • MixedLevel 就是Statement和Row混合使用。

    具体使用哪种日志,需要根据实际情况来决定。例如一条UPDATE语句更新了很多的数据,采用Statement会更加节省空间,但是相对的,Row会更加的可靠。


    InnoDB和MyISAM的区别

     

    由于MyISAM并不常用,不打算去深究其底层的一些原理和实现。我们在这里简单的对比一下这两个存储引擎的区别就好。我们分点来一点点描述。

    • 事务 InnoDB支持事务、回滚、事务安全和奔溃恢复。而MyISAM不支持,但查询的速度要比InnoDB更快
    • 主键 InnoDB规定,如果没有设置主键,就自动的生成一个6字节的主键,而MyISAM允许没有任何索引和主键的存在,索引就是行的地址
    • 外键 InnoDB支持外键,而MyISAM不支持
    • 表锁 InnoDB支持行锁表锁,而MyISAM只支持表锁
    • 全文索引 InnoDB不支持全文索引,但是可以用插件来实现相应的功能,而MyISAM是本身就支持全本索引
    • 行数 InnoDB获取行数时,需要扫全表。而MyISAM保存了当前表的总行数,直接读取即可。

    所以,简单总结一下,MyISAM只适用于查询大于更新的场景,如果你的系统查询的情况占绝大多数(例如报表系统)就可以使用MyISAM来存储,除此之外,都建议使用InnoDB。

     

    展开全文
  • 其实存储引擎也很简单,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。 有哪些已有的存储引擎可以让我们选择呢? InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated...

    存储引擎

    很多文章都是直接开始介绍有哪些存储引擎,并没有去介绍存储引擎本身。那么究竟什么是存储引擎?不知道大家有没有想过,MySQL是如何存储我们丢进去的数据的?

    其实存储引擎也很简单,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。

    有哪些已有的存储引擎可以让我们选择呢?

    InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated、Example

    种类很多,但是常用的存储引擎目前就只有InnoDB和MyISAM,我也会着重来介绍这两种存储引擎。

    InnoDB是目前使用最广的MySQL存储引擎,MySQL从5.5版本开始InnoDB就已经是默认的存储引擎了。那你知道为什么InnoDB被广泛的使用呢?先把这个问题放一放,我们先来了解一下InnoDB存储引擎的底层原理。

    InnoDB的内存架构主要分为三大块,缓冲池(Buffer Pool)、重做缓冲池(Redo Log Buffer)和额外内存池

    缓冲池

    InnoDB为了做数据的持久化,会将数据存储到磁盘上。但是面对大量的请求时,CPU的处理速度和磁盘的IO速度之间差距太大,为了提高整体的效率, InnoDB引入了缓冲池

    当有请求来查询数据时,如果缓存池中没有,就会去磁盘中查找,将匹配到的数据放入缓存池中。同样的,如果有请求来修改数据,MySQL并不会直接去修改磁盘,而是会修改已经在缓冲池的页中的数据,然后再将数据刷回磁盘,这就是缓冲池的作用,加速读,加速写,减少与磁盘的IO交互。

    缓冲池说白了就是把磁盘中的数据丢到内存,那既然是内存就会存在没有内存空间可以分配的情况。所以缓冲池采用了LRU算法,在缓冲池中没有空闲的页时,来进行页的淘汰。但是采用这种算法会带来一个问题叫做缓冲池污染

    当你在进行批量扫描甚至全表扫描时,可能会将缓冲池中的热点页全部替换出去。这样以来可能会导致MySQL的性能断崖式下降。所以InnoDB对LRU做了一些优化,规避了这个问题。

    MySQL采用日志先行,在真正写数据之前,会首先记录一个日志,叫Redo Log,会定期的使用CheckPoint技术将新的Redo Log刷入磁盘,这个后面会讲。

    除了数据之外,里面还存储了索引页、Undo页、插入缓冲、自适应哈希索引、InnoDB锁信息和数据字典。下面选几个比较重要的来简单聊一聊。

    插入缓冲

    插入缓冲针对的操作是更新或者插入,我们考虑最坏的情况,那就是需要更新的数据都不在缓冲池中。那么此时会有下面两种方案。

    1. 来一条数据就直接写入磁盘
    2. 等数据达到某个阈值(例如50条)才批量的写入磁盘

    很明显,第二种方案要好一点,减少了与磁盘IO的交互。

    两次写

    鉴于都聊到了插入缓冲,我就不得不需要提一嘴两次写,因为我认为这两个InnoDB的特性是相辅相成的。

    插入缓冲提高了MySQL的性能,而两次写则在此基础上提高了数据的可靠性。我们知道,当数据还在缓冲池中的时候,当机器宕机了,发生了写失效,有Redo Log来进行恢复。但是如果是在从缓冲池中将数据刷回磁盘的时候宕机了呢?

    这种情况叫做部分写失效,此时重做日志就无法解决问题。

    图片来源于网络, 侵删

    在刷脏页时,并不是直接刷入磁盘,而是copy到内存中的Doublewrite Buffer中,然后再拷贝至磁盘共享表空间(你可以就理解为磁盘)中,每次写入1M,等copy完成后,再将Doublewrite Buffer中的页写入磁盘文件。

    有了两次写机制,即使在刷脏页时宕机了,在实例恢复的时候也可以从共享表空间中找到Doublewrite Buffer的页副本,直接将其覆盖原来的数据页即可。

    自适应哈希索引

    自适应索引就跟JVM在运行过程中,会动态的把某些热点代码编译成Machine Code一样,InnoDB会监控对所有索引的查询,对热点访问的页建立哈希索引,以此来提升访问速度。

    你可能多次看到了一个关键字,接下来那我们就来聊一下页是什么?

    ,是InnoDB中数据管理的最小单位。当我们查询数据时,其是以页为单位,将磁盘中的数据加载到缓冲池中的。同理,更新数据也是以页为单位,将我们对数据的修改刷回磁盘。每页的默认大小为16k,每页中包含了若干行的数据,页的结构如下图所示。

    图片来源于网络, 侵删

    不用太纠结每个区是干嘛的,我们只需要知道这样设计的好处在哪儿。每一页的数据,可以通过FileHeader中的上一下和下一页的数据,页与页之间可以形成双向链表。因为在实际的物理存储上,数据并不是连续存储的。你可以把他理解成G1的Region在内存中的分布。

    而一页中所包含的行数据,行与行之间则形成了单向链表。我们存入的行数据最终会到User Records中,当然最初User Records并不占据任何存储空间。随着我们存入的数据越来越多,User Records会越来越大,Free Space的空间会越来越小,直到被占用完,就会申请新的数据页。

    User Records中的数据,是按照主键id来进行排序的,当我们按照主键来进行查找时,会沿着这个单向链表一直往后找,

    重做日志缓冲

    上面聊过,InnoDB中缓冲池中的页数据更新会先于磁盘数据更新的,InnoDB也会采用日志先行(Write Ahead Log)策略来刷新数据,什么意思呢?当事务开始时,会先记录Redo Log到Redo Log Buffer中,然后再更新缓冲池页数据。

    Redo Log Buffer中的数据会按照一定的频率写到重做日志中去。被更改过的页就会被标记成脏页,InnoDB会根据CheckPoint机制来将脏页刷到磁盘。

    日志

    上面提到了Redo log,这一小节就专门来讲一讲日志,日志分为如下两个维度。

    MySQL层面

    InnoDB层面

    MySQL日志

    MySQL的日志可以分为错误日志、二进制文件、查询日志和满查询日志。

    • 错误日志 很好理解,就是服务运行过程中发生的严重错误日志。当我们的数据库无法启动时,就可以来这里看看具体不能启动的原因是什么
    • 二进制文件 它有另外一个名字你应该熟悉,叫Binlog,其记录了对数据库所有的更改。
    • 查询日志 记录了来自客户端的所有语句
    • 慢查询日志 这里记录了所有响应时间超过阈值的SQL语句,这个阈值我们可以自己设置,参数为long_query_time,其默认值为10s,且默认是关闭的状态,需要手动的打开。

    InnoDB日志

    InnoDB日志就只有两种,Redo Log和Undo Log,

    • Redo Log 重做日志,用于记录事务操作的变化,且记录的是修改之后的值。不管事务是否提交都会记录下来。例如在更新数据时,会先将更新的记录写到Redo Log中,再更新缓存中页中的数据。然后按照设置的更新策略,将内存中的数据刷回磁盘。

    • Undo Log 记录的是记录的事务开始之前的一个版本,可用于事务失败之后发生的回滚。

    Redo Log记录的是具体某个数据页上的修改,只能在当前Server使用,而Binlog可以理解为可以给其他类型的存储引擎使用。这也是Binlog的一个重要作用,那就是主从复制,另外一个作用是数据恢复

    上面提到过,Binlog中记录了所有对数据库的修改,其记录日志有三种格式。分别是Statement、Row和MixedLevel。

    • Statement 记录所有会修改数据的SQL,其只会记录SQL,并不需要记录下这个SQL影响的所有行,减少了日志量,提高了性能。但是由于只是记录执行语句,不能保证在Slave节点上能够正确执行,所以还需要额外的记录一些上下文信息
    • Row 只保存被修改的记录,与Statement只记录执行SQL来比较,Row会产生大量的日志。但是Row不用记录上下文信息了,只需要关注被改成啥样就行。
    • MixedLevel 就是Statement和Row混合使用。

    具体使用哪种日志,需要根据实际情况来决定。例如一条UPDATE语句更新了很多的数据,采用Statement会更加节省空间,但是相对的,Row会更加的可靠。

    InnoDB和MyISAM的区别

    由于MyISAM并不常用,我也不打算去深究其底层的一些原理和实现。我们在这里简单的对比一下这两个存储引擎的区别就好。我们分点来一点点描述。

    • 事务 InnoDB支持事务、回滚、事务安全和奔溃恢复。而MyISAM不支持,但查询的速度要比InnoDB更快
    • 主键 InnoDB规定,如果没有设置主键,就自动的生成一个6字节的主键,而MyISAM允许没有任何索引和主键的存在,索引就是行的地址
    • 外键 InnoDB支持外键,而MyISAM不支持
    • 表锁 InnoDB支持行锁表锁,而MyISAM只支持表锁
    • 全文索引 InnoDB不支持全文索引,但是可以用插件来实现相应的功能,而MyISAM是本身就支持全本索引
    • 行数 InnoDB获取行数时,需要扫全表。而MyISAM保存了当前表的总行数,直接读取即可。

    所以,简单总结一下,MyISAM只适用于查询大于更新的场景,如果你的系统查询的情况占绝大多数(例如报表系统)就可以使用MyISAM来存储,除此之外,都建议使用InnoDB。

    End

    由于时间的原因,本文只是简单的聊了聊InnoDB的整体架构,并没有很深入的去聊某些点。例如InnoDB是如何改进来解决缓冲池污染的,其算法具体是什么,checkpoint是如何工作的等等,只是做一个简单的了解,之后如果有时间的话再细聊。

    往期文章:

    如果你觉得这篇文章对你有帮助,还麻烦点个赞关个注分个享留个言

    也可以微信搜索公众号【SH的全栈笔记】,当然也可以直接扫描二维码关注

    展开全文
  • 【第一章】innodb行格式 1、我们要查某一条或者某多条数据的时候,是怎么样在计算机里面(innodb)进行查询运算的? 首先我们要知道一条数据显示在屏幕上其实是一个逻辑的一个视界。 我们查询数据,首先是将数据...
  • 1.Innodb 引擎的底层实现(聚集索引方式) InnoDB 是聚集索引方式,因此数据和索引都存储在同一个文件里。首先 InnoDB 会根据主键 ID 作为 KEY 建立索引 B+树,如左下图所示,而 B+树的叶子节点存储的是主键 ID 对应...
  • 很多文章都是直接开始介绍有哪些存储引擎,...其实存储引擎也很简单,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。 有哪些已有的存储引擎可以让我们选择呢? InnoDB、MyISAM、Memory、
  • MySQL存储引擎MyISAM和InnoDB底层索引结构

    万次阅读 多人点赞 2018-10-10 11:29:36
    二 MyISAM和InnoDB对索引和数据的存储在磁盘上是如何体现的 三 MyISAM主键索引与辅助索引的结构 1. 主键索引: 2. 辅助(非主键)索引: 四 InnoDB主键索引与辅助索引的结构 1. 主键索引: 2. 辅助(非主键)...
  • 相同: 都是mysql自带的存储引擎。 区别: ... 两者底层都采用的数据结构是B+树,但是实现方式又略有不同。MyIsam的B+树采用的是非聚集索引(辅助索引),INNODB的B+树采用的聚集索引。 MyISA...
  • 在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。MyISAM索引实现MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是...
  • MySQL-07-引擎(InnoDB 和 Myisam)底层实现 MySQL的数据表的类型 : MyISAM , InnoDB等… 名称 MyISAM lnnoDB 事务处理 不支持 支持 数据行锁定 不支持 支持 外键约束 不支持 支持 全文索引 支持 不...
  • MySQL索引的底层实现(MyISAM和InnoDB)B+树MyISAM的索引实现InnoDB的索引实现 在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的。 B+树 MyISAM和InnoDB都使用了B+树,如果想学习一下B...
  • 什么是MVCC? MVCC是Multi-Version Concurrency Control(多版本并发控制...InnoDB对MVCC的实现采用的是乐观并发控制。 InnoDB-MVCC如何实现? 在《高性能MySQL》一书中,关于InnoDB-MVCC的实现是这样介绍的: ...
  • 文章目录事务隔离级别底层的锁以及InnoDB的事务隔离级别实现事务隔离级别底层的锁先来说一下MVCCInnoDB事务隔离级别的实现记录锁(普通的行锁)间隙锁临键锁为什么可重复读和已提交读都使用了MVCC,但是可重复读解决...
  • innodb行锁实现方式

    2014-12-04 09:40:00
    Innodb行锁是通过给索引上的索引想加锁来实现的,这点Mysql与Oracle不同,Oracle是通过在数据块中对相应数据行加锁来实现的。 Innodb的行锁实现方式导致了只有通过索引条件检索数据,Innodb才使用行级锁,否则...
  • Mysql InnoDB行锁实现方式

    千次阅读 2018-09-03 14:02:05
    简述:InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,...
  • 在之前的博客中有说到InnoDB存储引擎的主要工作都是在一个单独的后台线程Master Thread中实现的,现在我们来讲解一下Master Thread的工作方式 1. 1.0.x版本之前的Master Thread 1.1 Master Thread概述 Master ...
  • MySQL索引底层实现原理 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。 我们知道,数据库查询是数据库的最主要功能之一。我们都...
  • MySQL innoDB索引底层原理详解

    万次阅读 多人点赞 2016-09-02 21:25:22
    本文介绍MySQL的InnoDB索引相对底层原理相关知识,涉及到B+Tree索引和Hash索引,但本文主要介绍B+Tree索引,其中包括聚簇索引和非聚簇索引,InnoDB数据页结构详解,B+Tree索引的使用以及优化,同时还有B+Tree索引的...
  • 可重复读的实现  Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(读已经提交的,其实是读早于本事务开始且已经提交的),但是不能看到其他事务对已有记录的更新(即...
  • InnoDB MVCC实现原理及源码解析

    千次阅读 2018-04-15 15:44:38
    1、原理介绍数据多版本(MVCC)是MySQL实现高性能的一个主要的一个主要方式,通过对普通的SELECT不加锁,直接利用MVCC读取指版本的值,避免了对数据重复加锁的过程。InnoDB支持MVCC多版本,其中RC和RR隔离级别是利用...
  • 其实存储引擎也很简单,我认为就是一种存储解决方案,实现了新增数据、更新数据和建立索引等等功能。 有哪些已有的存储引擎可以让我们选择呢? InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated...
  • 1、索引数据结构2、InnoDB索引的设计(1)计算机原理(2)查找过程(3)聚族索引与二级索引(4)创建索引及索引的类型(5)索引的缺点(6)外键及作用 1、索引数据结构 哈希索引(Hash indexes)采用哈希表来对键值...
  • innodb底层实现笔记

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,486
精华内容 11,794
关键字:

innodb底层如何实现