精华内容
参与话题
问答
  • 主要介绍了java连接mysql底层封装,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Mysql底层索引详解

    2019-10-05 19:57:55
    1,

    索引是帮助MySQL高效获取数据的排好序的数据结构。

    索引本质以及索引类型:
    在这里插入图片描述
    MySQL底层索引的数据结构是B+Tree(B-Tree变种)

    1. 非叶子节点不存储data,只存储索引,可以放更多的索引;
    2. 顺序访问指针,提高区间访问的性能。
      在这里插入图片描述
      B+Tree树节点的大小为16KB,每个树的的结点会被load到内存,每次和磁盘进行一次IO操作(比较耗时)。
    3. 一个索引的内存大小为8B,指针的内存大小为6B,所以一个索引的实际大小为14B(字节)。
    4. 16KB / 14B 约等于1170,所以一个B+Tree树节点可以存放1170个索引。那么第二层的索引个数大约为1170 * 1170个。
    5. 毛估第三层一个索引+对应的数据的大小为1KB,那么第三层一个叶子节点可以包含16KB / 1KB = 16个索引。那么这样下来**B+Tree的三层可以存放1170 x 1170 x 16 = 2千多万个索引。**
      在这里插入图片描述

    1,为什么不使用Hash作为索引方法?
    答:不支撑范围查询。select * from student where id > 10;
    B+Tree可以支撑范围查找,因为他有一个指针指向下一个索引。如图:
    在这里插入图片描述

    数据库的表结构,数据,索引的存放位置:

    在这里插入图片描述
    MySQL表的存储引擎为MyISAM:

    1. frm文件存放表结构;
    2. MYD文件存放表中的数据;
    3. MYI文件存放表的索引。
      在这里插入图片描述
      在这里插入图片描述
      MyISAM存储引擎的查找过程:
      1,将B+Tree的索引节点load到内存,进行比较,依次往树的下面寻找;
      2,最后在树的叶子节点找到与之对应的索引值,而索引的data存放的是:索引所在数据行的磁盘文件指针(如上图:Ox90);
      3,根据该指针,把数据从数据表中查询出来即可。
      该过程查找了2个文件,一个MYI文件,一个MYD文件;相比InnoDB多了一个磁盘IO。

    MySQL表的存储引擎为InnoDB:

    1,frm文件存放表结构;
    2,ibd文件存放索引和数据。
    在这里插入图片描述
    InnoDB存储引擎的查找过程:
    1,将B+Tree的索引节点load到内存,进行比较,依次往树的下面寻找;
    2,最后在树的叶子节点找到与之对应的索引值,而索引的data存放的是:索引对应行的数据;
    该过程只查找了1个文件,ibd文件,相比MyISAM存储引擎少了一次磁盘IO。
    在这里插入图片描述

    1,什么是聚集索引?

    • 聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况,所以,对应的聚集索引只能有一个。

    • 聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。

    • InnoDB的主键索引就是聚集索引,叶子节点包含了完整的数据记录,数据和索引存储在同一个文件;MyISAM的主键索引就是非聚集索引,索引存储在MYI文件,数据存储在MYD文件。

    2,InnoDB表必须有主键,并且推荐使用整型的自增主键?

    • 如果InnoDB表没有设置主键,后台会自动生成一个主键,所以必须自己建,没必要MySQL帮我们再加一个字段,占用内存;
    • 如果使用UUID作为主键,在进行比较时(abc3f,abcdf 转成ASCII码进行比较) 没有整型数据大小比较快;
    • 如果不是自增,假如叶子节点达到16个满了,再生成一个索引时,恰好索引值大小处于该叶子节点的中间,导致叶子节点要拆分,增加了B+Tree的层级,减慢了索引查找的性能。如下图:
      在这里插入图片描述

    Innodb的非主键索引(负索引)查找逻辑:

    先根据name找到ID,然后根据ID找到对应的数据
    在这里插入图片描述

    在这里插入图片描述

    b树和b+树的区别:b树和b+树的区别聚集索引和非聚集索引的区别

    展开全文
  • MySQL MVCC底层原理详解

    千次阅读 2020-07-25 05:46:44
    MySQL MVCC底层原理详解

    1 简介

    MVCC(Multi-Version Concurrency Control)多版本并发控制,是用来在数据库中控制并发的方法,实现对数据库的并发访问用的。在MySQL中,MVCC只在读取已提交(Read Committed)可重复读(Repeatable Read)两个事务级别下有效。其是通过Undo日志中的版本链ReadView一致性视图来实现的。MVCC就是在多个事务同时存在时,SELECT语句找寻到具体是版本链上的哪个版本,然后在找到的版本上返回其中所记录的数据的过程。

    首先需要知道的是,在MySQL中,会默认为我们的表后面添加三个隐藏字段:

    • DB_ROW_ID:行ID,MySQL的B+树索引特性要求每个表必须要有一个主键。如果没有设置的话,会自动寻找第一个不包含NULL的唯一索引列作为主键。如果还是找不到,就会在这个DB_ROW_ID上自动生成一个唯一值,以此来当作主键(该列和MVCC的关系不大);
    • DB_TRX_ID:事务ID,记录的是当前事务在做INSERT或UPDATE语句操作时的事务ID(DELETE语句被当做是UPDATE语句的特殊情况,后面会进行说明);
    • DB_ROLL_PTR:回滚指针,通过它可以将不同的版本串联起来,形成版本链。相当于链表的next指针。

    (注意,添加的隐藏字段并不是很多人认为的创建时间和删除时间,同时在MySQL中MVCC的实现也不是通过什么快照来实现的。之所以有这种说法可能是源自于《高性能MySQL》一书中对MySQL中MVCC的错误结论,然后就人云亦云传开了(注意,我这里一直强调的是MySQL中MVCC的实现,是因为在不同的数据库中可能会有不同的实现)。所以说看源码和看官方文档才是最权威的解释)


    2 ReadView

    ReadView一致性视图主要是由两部分组成:所有未提交事务的ID数组已经创建的最大事务ID组成(实际上ReadView还有其他的字段,但不影响这里对MVCC的讲解)。比如:[100,200],300。事务100和200是当前未提交的事务,而事务300是当前创建的最大事务(已经提交了)。当执行SELECT语句的时候会创建ReadView,但是在读取已提交和可重复读两个事务级别下,生成ReadView的策略是不一样的:读取已提交级别是每执行一次SELECT语句就会重新生成一份ReadView,而可重复读级别是只会在第一次SELECT语句执行的时候会生成一份,后续的SELECT语句会沿用之前生成的ReadView(即使后面有更新语句的话,也会继续沿用)。


    3 版本链

    所有版本的数据都只会存一份,然后通过回滚指针连接起来,之后就是通过一定的规则找到具体是哪个版本上的数据就行了。假设现在有一张account表,其中有id和name两个字段,那么版本链的示意图如下:

    而具体版本链的比对规则如下,首先从版本链中拿出最上面第一个版本的事务ID开始逐个往下进行比对:

    (其中min_id指向ReadView中未提交事务数组中的最小事务ID,而max_id指向ReadView中的已经创建的最大事务ID)

    • 如果落在绿色区间(DB_TRX_ID < min_id):这个版本比min_id还小(事务ID是从小往大顺序生成的),说明这个版本在SELECT之前就已经提交了,所以这个数据是可见的。或者(这里是短路或,前面条件不满足才会判断后面这个条件)这个版本的事务本身就是当前SELECT语句所在事务的话,也是一样可见的
    • 如果落在红色区间(DB_TRX_ID > max_id):表示这个版本是由将来启动的事务来生成的,当前还未开始,那么是不可见的;
    • 如果落在黄色区间(min_id <= DB_TRX_ID <= max_id):这个时候就需要再判断两种情况:
      • 如果这个版本的事务ID在ReadView的未提交事务数组中,表示这个版本是由还未提交的事务生成的,那么就是不可见的;
      • 如果这个版本的事务ID不在ReadView的未提交事务数组中,表示这个版本是已经提交了的事务生成的,那么是可见的。

    如果在上述的判断中发现当前版本是不可见的,那么就继续从版本链中通过回滚指针拿取下一个版本来进行上述的判断。


    4 演示过程

    下面通过一个示例来具体演示MVCC的执行过程(假设是在可重复读事务级别下),当前account表中已经有了一条初始数据(id=1,name=monkey):

      Transaction 100 Transaction 200 Transaction 300 无事务ID 无事务ID
    1 begin; begin; begin; begin; begin;
    2 UPDATE test SET a='1' WHERE id = 1;         
    3   UPDATE test SET a='2' WHERE id = 2;       
    4     UPDATE account SET name = 'monkey301' WHERE id = 1;    
    5     commit;    
    6       SELECT name FROM account WHERE id = 1;  
    7 UPDATE account SET name = 'monkey101' WHERE id = 1;        
    8 UPDATE account SET name = 'monkey102' WHERE id = 1;        
    9       SELECT name FROM account WHERE id = 1;  
    10 commit; UPDATE account SET name = 'monkey201' WHERE id = 1;      
    11   UPDATE account SET name = 'monkey202' WHERE id = 1;      
    12       SELECT name FROM account WHERE id = 1; SELECT name FROM account WHERE id = 1;
    13   commit;      

    从左往右分别是五个事务,从上到下是时刻点。其中在第2和3时刻点中事务100和事务200(这里两个事务之间相差100只是为了更加方便去看,正常来说下个事务的ID是以+1的方式来创建的)分别执行了一条UPDATE语句,这两条语句并无实际作用,只是为了生成事务ID的,所以在下面的MVCC执行过程中就不分析这两条语句所带来的影响了,我们只研究account表。而其中最后两个事务,我是注明没有事务ID的。因为事务ID是执行一条更新操作(增删改)的语句后才会生成(这也是事务100和事务200要先执行一条更新语句的意义),并不是开启事务的时候就会生成。最后两个事务中可以看到就是执行了一些SELECT语句而已,所以它们并没有事务ID。

    首先来看一下初始状态时的版本链和ReadView(ReadView此时还未生成):

    其中事务1在account表中创建了一条初始数据。

    之后在第1时刻点,五个事务分别开启了事务(如上所说,这个时候还没有生成事务ID)。

    在第2时刻点,第一个事务执行了一条UPDATE语句,生成了事务ID为100。

    在第3时刻点,第二个事务执行了一条UPDATE语句,生成了事务ID为200。

    在第4时刻点,第三个事务执行了一条UPDATE语句,将account表中id为1的name改为了monkey301。同时生成了事务ID为300。

    在第5时刻点,事务300也就是上面的事务执行了commit操作。

    在第6时刻点,第四个事务执行了一条SELECT语句,想要查询一下当前id为1的数据(如上所说,该事务没有生成事务ID)。此时的版本链和ReadView如下:

    因为在第5时刻点,事务300已经commit了,所以ReadView的未提交事务数组中不包含它。此时根据上面所说的比对规则,拿版本链中的第一个版本的事务ID为300进行比对,首先当前这条SELECT语句没有在事务300中进行查询,然后发现是落在黄色区间,而且事务300也没有在ReadView的未提交事务数组中,所以是可见的。即此时在第6时刻点,第四个事务所查找到的结果是monkey301。

    在第7时刻点,事务100执行了一条UPDATE语句,将account表中id为1的name改为了monkey101。

    在第8时刻点,事务100又执行了一条UPDATE语句,将account表中id为1的name改为了monkey102。

    在第9时刻点,第四个事务执行了一条SELECT语句,想要查询一下当前id为1的数据。此时的版本链和ReadView如下:

    注意,因为当前是在可重复读的事务级别下,所以此时的ReadView沿用了在第6时刻点生成的ReadView(如果是在读取已提交的事务级别下,此时就会重新生成一份ReadView了)。然后根据上面所说的比对规则,拿版本链中的第一个版本的事务ID为100进行比对,首先当前这条SELECT语句没有在事务100中进行查询,然后发现是落在黄色区间,而且事务100是在ReadView的未提交事务数组中,所以是不可见的。此时通过回滚指针拿取下一个版本,发现事务ID仍然为100,经过分析后还是不可见的。此时又拿取下一个版本:事务ID为300进行比对,首先当前这条SELECT语句没有在事务300中进行查询,然后发现是落在黄色区间,但是事务300没有在ReadView的未提交事务数组中,所以是可见的。即此时在第9时刻点,第四个事务所查找到的结果仍然是monkey301(这也就是可重复读的含义)。

    在第10时刻点,事务100commit提交事务了。同时事务200执行了一条UPDATE语句,将account表中id为1的name改为了monkey201。

    在第11时刻点,事务200又执行了一条UPDATE语句,将account表中id为1的name改为了monkey202。

    在第12时刻点,第四个事务执行了一条SELECT语句,想要查询一下当前id为1的数据。此时的版本链和ReadView如下:

    跟第9时刻点一样,在可重复读的事务级别下,ReadView沿用了在第6时刻点生成的ReadView。然后根据上面所说的比对规则,拿版本链中的第一个版本的事务ID为200进行比对,首先当前这条SELECT语句没有在事务200中进行查询,然后发现是落在黄色区间,而且事务200是在ReadView的未提交事务数组中,所以是不可见的。此时通过回滚指针拿取下一个版本,发现事务ID仍然为200,经过分析后还是不可见的。此时又拿取下一个版本:事务ID为100进行比对,首先当前这条SELECT语句没有在事务100中进行查询,然后发现是落在黄色区间内,同时在ReadView的未提交数组中,所以依然是不可见的。此时又拿取下一个版本,发现事务ID仍然为100,经过分析后还是不可见的。此时再拿取下一个版本:事务ID为300进行比对,首先当前这条SELECT语句没有在事务300中进行查询,然后发现是落在黄色区间,但是事务300没有在ReadView的未提交事务数组中,所以是可见的。即此时在第12时刻点,第四个事务所查找到的结果仍然是monkey301。

    同时在第12时刻点,第五个事务执行了一条SELECT语句,想要查询一下当前id为1的数据。此时的版本链和ReadView如下:

    注意,此时第五个事务因为是该事务内的第一条SELECT语句,所以会重新生成在当前情况下的ReadView,即上图中所示的内容。可以看到,和第四个事务生成的ReadView并不一样,因为在之前的第10时刻点,事务100已经提交事务了。然后根据上面所说的比对规则,拿版本链中的第一个版本的事务ID为200进行比对,首先当前这条SELECT语句没有在事务200中进行查询,然后发现是落在黄色区间,而且事务200是在ReadView的未提交事务数组中,所以是不可见的。此时通过回滚指针拿取下一个版本,发现事务ID仍然为200,经过分析后还是不可见的。此时又拿取下一个版本:事务ID为100进行比对,发现是在绿色区间,所以是可见的。即此时在第12时刻点,第五个事务所查找到的结果是monkey102(可以看到,即使是同一条SELECT语句,在不同的事务中,查询出来的结果也可能是不同的,究其原因就是因为ReadView的不同)。

    在第13时刻点,事务200执行了commit操作,整段分析过程结束。

    以上演示的就是MVCC的具体执行过程,在多个事务下,版本链和ReadView是如何配合进行查找的。上面还遗漏了一种情况没有进行说明,就是如果是DELETE语句的话,也会在版本链上将最新的数据插入一份,然后将事务ID赋值为当前进行删除操作的事务ID。但是同时会在该条记录的信息头(record header)里面的deleted_flag标记位置为true,以此来表示当前记录已经被删除。所以如果经过版本比对后发现找到的版本上的deleted_flag标记位为true的话,那么也不会返回,而是继续寻找下一个。

    另外,如果当前事务执行rollback回滚的话,会把版本链中属于该事务的所有版本都删除掉。

    展开全文
  • 1、MySQL整体架构 在执行到存储引擎这一步骤时,会根据具体的存储引擎,去磁盘获取数据。 2、InnoDB是如何执行Update语句? 下面只是讲解整个大流程,未涉及细节,细节会在后续陆续分享 比如我们现在要执行 update...

    更多精彩内容请关注


    1、MySQL整体架构

    在这里插入图片描述

    在执行到存储引擎这一步骤时,会根据具体的存储引擎,去磁盘获取数据。

    2、InnoDB是如何执行Update语句?

    下面只是讲解整个大流程,未涉及细节,细节会在后续陆续分享
    在这里插入图片描述

    比如我们现在要执行 update users set name=‘小张’ where id=1

    1. 到存盘上找到需要更新的数据,比如数据为 id=1,name=小李,将数据放到缓存池中(Buffer Pool)

    2. 将查询出来的值( id=1,name=小李)写到undo日志文件中,目的是后期数据回滚,先将原来值记录下来,回滚的时候就从该日志中取出来,以后会相信分享undo日志详细内容

    3. 更新Buffer Pool中的值,改为name由小李-》小张

    4. 写到将更新操作记录一下,写到Redo log buffer(内存)中

    5. Redo log buffer中的数据持久化到磁盘Redo log文件中,这个时候就算是更新成功了,为什么要用Redo log,以及带来的好处,后续会分享,现在主要了解到整体的流程就行。

      这里有个参数可以设置,redo log持久化策略:innodb_flush_log_at_trx_commit,可配置为:0,1,2

      • 配置为0:提交事务的时候,不会持久化到redo日志文件中,这个时候宕机,会造成数据丢失

      • 配置为1:提交事务redo log从内存刷入到磁盘文件里去,只要事务提交成功,那么redo log就必然在磁盘里了

      • 配置为2:提交事务的时候,把redo日志写os cache缓存,而不是直接进入磁盘文件,可能1秒后再持久化到磁盘,和配置为0类似,会造成数据丢失。

    6. 写入binlog日志,binlog实际上是对哪个数据做了什么修改,和Redo log buffer类似,也是有刷盘策略:sync_binlog和innodb_flush_log_at_trx_commit类似

    7. 将binlog的记录写入到Redo日志中,为什么要做个标记呢?

      用来保持redo log日志与binlog日志一致的。必须是在redo log中写入最终的事务commit标记了,然后此时事务提交成功,而且redo log里有本次更新对应的日志,binlog里也有本次更新对应的日志 ,redo log和binlog完全是一致的,这个时候我们才认为是提交成功的

    8. 异步IO线程将修改后的数据刷到磁盘文件中

    3、讨论下步骤2可能出现的问题

    首先,步骤1,2,3,4中任何一步出问题,都不会有什么影响,因为所有的数据修改都是基于内存的,还没做持久化,数据库数据还是修改前的数据。

    可能会出现问题是,写进redo log后MySQL宕机,这个时候,我们已经默认该数据修改成功,但是实际上,知识记录到redo log,并没有改到数据库里面正式的数据。MySQL的机制是,当MySQL宕机重启时,会去redo log中拿到之前放进的更新数据,再放到buffer pool中,这样又可以继续执行下面的步骤了,将更新后的数据刷到磁盘,不会造成数据不一致。

    展开全文
  • 这里先挖个坑,整体总结了部分的脑图,大家可以大概了解一下,详细的讲解后面有时间会更新到下面。 同时附上我的视频讲解地址:

    在这里插入图片描述
    这里先挖个坑,整体总结了部分的脑图,大家可以大概了解一下,详细的讲解后面有时间会更新到下面。
    同时附上我的视频讲解地址:【未央君带你脑图快速复习 01】MySQL 存储及索引底层知识
    需要脑图源文件的可以扫码关注我的公众号回复:MySQL 索引底层脑图
    在这里插入图片描述

    展开全文
  • MySQL innoDB索引底层原理详解

    万次阅读 多人点赞 2016-09-02 21:25:22
    本文介绍MySQL的InnoDB索引相对底层原理相关知识,涉及到B+Tree索引和Hash索引,但本文主要介绍B+Tree索引,其中包括聚簇索引和非聚簇索引,InnoDB数据页结构详解,B+Tree索引的使用以及优化,同时还有B+Tree索引的...
  • 参考文章:mysql的索引底层原理 什么是索引 概念:索引是提高mysql查询效率的数据结构。总的一句话概括就是索引是一种数据结构。 数据库查询是数据库的最主要功能之一。设计者们都希望查询数据的速度能尽可能的...
  • 上篇博客,我们详细的说明了mysql的索引存储结构,也就是我们的B+tree的变种,是一个带有双向链表的B+tree。那么我今天来详细研究一下,怎么使用索引和怎么查看索引的使用情况。 我们先来简单的建立几张表。   ...
  • MYSQL中的索引及底层原理详解 索引介绍 1.有关概念: 定义:创建在表上,对数据库表中的一列或者多列的值进行排列得到的结果(相当于表中数据的向导)。 工作方式:一个表创建的索引以文件的形式存储下来,要用该表...
  • 主要介绍了MySQL8新特性之降序索引底层实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 题外话:中华文化博大进深,从学Java到数据库,无一不体现出同一组件鱼和熊掌不可兼得的要义。...好了,Talk is cheap,show you the code:测试环境:Mysql 5.7.20-log,IDEA 2018首先创建两张表: testinnodb,te...
  • 摘要本文介绍MySQL的InnoDB索引相对底层原理相关知识,涉及到B+Tree索引和Hash索引,但本文主要介绍B+Tree索引,其中包括聚簇索引和非聚簇索引,InnoDB数据页结构详解,B+Tree索引的使用以及优化,同时还有B+Tree...
  • mysql底层原理

    2019-04-21 16:42:00
    1、索引底层数据结构B+Tree详解 索引的本质 索引是帮助MySQL高效获取数据的排好序的数据结构 索引存储在文件里 索引的结构 二叉树 (红黑树[平衡二叉树])、HASH、BTREE【多叉树】 索引为什么不使用二叉树来...
  • mySql 引擎详解

    2019-06-24 18:56:26
    mySql存储数据时,有不同的存储方式,这些方式都使用了不同的底层实现(如:存储机制,索引技巧,索引技巧,锁定水平),底层实现的差异带来的功能也就不同。在不同的场景下使用合适的存储方式就能让你的数据读写...
  • 题外话:中华文化博大进深,从学Java到数据库,无一不体现出同一组件鱼和熊掌不可兼得的要义。自然,编程中安全和效率也很难同时做到...测试环境:Mysql 5.7.20-log,IDEA 2018 首先创建两张表: testinnodb,testmyi...
  • MySQL引擎详解

    2017-05-31 16:55:18
    它处于MySQL体系架构中Server端底层,是底层物理结构的实现,用于将数据以各种不同的技术方式存储到文件或者内存中,不同的存储引擎具备不同的存储机制、索引技巧和锁定水平。常见的MySQL存储引擎有InnoDB、MyISAM、...
  • mySql索引详解

    2019-07-10 10:34:29
    哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快。其余大部分场景,建议选择BTree索引。 BTree索引在(MyISAM和InnoDB)的不同实现方式...
  • MySQL中InnoDB存储引擎之前是不支持全文检索的,要使用全文检索的话只能使用MySIAM存储引擎,但是在1.2.x版本开始就支持全文检索了 1.2 问题的引入 MySql中的InnoDB存储引擎中对于表索引的管理是采用B+树结构的,...
  • MySQL详解

    2020-05-04 15:29:29
    概述 按使用方式 乐观锁 概述 假设在极大多数情况下不会形成冲突,只有在数据提交的时候,才会对数据是否产生冲突进行检验。如果数据产生冲突了,则返回错误...乐观锁不需要数据库底层的支持 悲观锁 概述 悲观锁...
  • Mysql索引详解

    2018-01-08 16:22:00
    索引有很多种类型,如:B-tree索引、哈希索引、空间数据索引R-TREE 、全文索引、主键索引等,在Mysql 中,索引是在存储引擎层而不是服务器层实现的。所以没有统一的索引标准——不同存储引擎的索引工作方式并 不一样...
  • MYSQL 索引详解

    2017-04-22 17:50:59
    索引是在MySQL的存储引擎层中实现的,而不是在服务层实现的。所以每种存储引擎的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型。即使多个存储引擎支持同一种类型的索引,其底层实现也可能不同。 ...

空空如也

1 2 3 4 5 ... 11
收藏数 220
精华内容 88
关键字:

mysql底层详解

mysql 订阅