全民编程都这么久了,你们怎么还不关注一下

Innodb的四个特性

全民编程都这么久了,你们怎么还不关注一下

innodb架构体系图

预读

在介绍Innodb预读特性之前,笔者有必要介绍一下操作系统的局部性原理,这样方便于读者理解Innodb的一个强大特性-----预读。

局部性原理

一个优秀额程序通常会有良好的局部性,所谓局部性指的是一个应用程序通常会重复使用某块内存区域中的数据,或者使用该区域邻近内存区域的数据。默认情况下当操作系统监测到某块内存区的数据将要被重复使用或者邻近的数据将要被使用时,操作系统会一次性将相邻的若干个数据块同时加载到内存缓冲区中。局部性原理分为以下两种:

时间局部性原理:时间局部性原理主要体现在某一块区域中的数据将要被重复使用
空间局部性原理,主要体现在相邻的数据块将要被使用,操作系统一次性将邻近的多个数据块一次性
通过IO读入内存缓冲区中,下面举个例子来证明空间局部性原理带来性能的提高:
package com.htym.bean;

public class LocalTest {

    public static void main(String[] args) {
        int[][] arr = new int[10000][10000];
        for(int i=0; i<10000; i++){
            for (int j=0; j<10000; j++){
                arr[i][j] = 1;
            }
        }
        long begin1 = System.currentTimeMillis();
        int sum = 0;
        for(int i=0; i<10000; i++){
            for (int j=0; j<10000; j++){
                sum += arr[i][j];	          //arr[0][0],arr[0][1],arr[0][2],arr[0][3],arr[0][04],arr[0][5].....相邻的数据块仅需通过一次IO操作全部加载到内存中
            }
        }
        System.out.println("结束时间:" + (System.currentTimeMillis() - begin1));
      
      --------------------------------------------------------------------------------------------------
        long begin2 = System.currentTimeMillis();
        sum = 0;
        for(int i=0; i<10000; i++){
            for (int j=0; j<10000; j++){
                sum += arr[j][i];					///arr[0][0],arr[1][0],arr[2][0],arr[3][0],arr[4][0],arr[5][0]
            }
        }
        System.out.println("结束时间:" + (System.currentTimeMillis() - begin2));
    }
}

最终输出结果:
结束时间:144
结束时间:3607

计算同一个二位数组的和但是耗时确相差20多倍,原因就在于数组为连续的内存空间,arr[0][0],arr[0][1],arr[0][2],arr[0][3],arr[0][04],arr[0][5]...
为相邻的数据块仅需通过一次IO操作全部加载到内存中,然而,///arr[0][0],arr[1][0],arr[2][0],arr[3][0],arr[4][0],arr[5][0]
并不是相邻的数据,操作系统只能一个一个的读取,每一次读取都是一次IO操作。

有了以上局部性原理的知识基础之后,我们再来理解预读的原理就相对简单多了。可以简单的理解为:当Innodb监测到某一块磁盘空间的数据将要被读取时邻近的数据很快将要被使用,Innodb会一次性仅通过一次IO操作将数据读取到内存缓冲池中。Innodb中预读包含两种模式:

顺序预读:如果Innodb监测到表空间的某个段的数据将要被使用并且其相邻的数据段也将要被使用,
那么Innodb将会一次性通过一次IO操作将数据批量读取到内存缓冲池当中
随机预读:如果InnoDB注意到表空间中的某些区域似乎正处于被完全读入缓冲池的过程中,它会将
剩余的读取发送到 I/O 系统

何时触发Innodb预读功能可以通过如下配置来控制

//顺序预读配置参数
Innodb_read_ahead_threshold: 配置参数 innodb_read_ahead_threshold 控制InnoDB检测顺序页面
访问模式的敏感程度。如果从一个extent顺序读取的page数大于等于 innodb_read_ahead_threshold,
则InnoDB启动后续整个extent的异步预读操作。 innodb_read_ahead_threshold可以设置为 0-64 之间的
任何值。默认值为 56。值越高,访问模式检查越严格。例如,如果您将该值设置为 48,则InnoDB 
仅当当前扩展区中的 48 个页面已按顺序访问时才会触发线性预读请求。如果值为 8,InnoDB即使按
顺序访问范围内少至 8 个页面,也会触发异步预读。您可以在 MySQL配置文件中设置该参数的值,或者
通过语句动态更改它 SET GLOBAL,这需要足够的权限来设置全局系统变量。

//------------------------------------------------------------------------------------------------------
//随机预读配置参数
innodb_random_read_ahead=ON:随机预读是一种技术,它根据缓冲池中已经存在的页面预测何时
可能很快需要页面,而不管读取这些页面的顺序如何。如果在缓冲池中找到来自同一extent的 13 个
连续页面,则 InnoDB异步发出请求以预取扩展区的剩余页面。要启用此功能,请将配置变量设置 
innodb_random_read_ahead为 ON

//-----------------------------------------------------------------------------------------------------

双写缓冲

双写缓冲区:双写缓冲是一种特殊的文件刷新技术,它涉及到一种称为双写缓冲区的数据结构。在默认情况下Innodb默认开启该功能(dubblewrite_buffer=ON),他增加意外退出和断电后的数据恢复的安全性,并减少文件同步(fsync())操作来提高数据库的性能。

在将页面写入数据文件之前,InnoDB 首先将它们写入称为双写缓冲区的连续表空间区域。只有在对双写缓冲区的写入和刷新完成后,才会InnoDB 将页面写入数据文件中的适当位置。如果在页面写入过程中存在操作系统、存储子系统或意外 的mysqld进程退出(导致页面撕裂的 情况),InnoDB则可以稍后在恢复期间从双写缓冲区中找到该页面的良好副本。

双写缓冲的实现过程对缓冲池的脏页进行刷新时,不是直接写磁盘,而是会通过memcpy()函数将脏页先复制到内存中的doublewrite buffer,之后通过doublewrite 再分两次,每次1M顺序地写入共享表空间的物理磁盘上,在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewrite buffer 中的页写入各个 表空间文件中,此时的写入则是离散的。如果操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,innodb可以从共享表空间中的doublewrite中找到该页的一个副本,将其复制到表空间文件,再应用重做日志

注意:将数据页写如文件的时候,Innodb会将数据写入redo log日志文件中,当完全写入redo log文件之后会设置一个prepare状态,然后再将数据写入dubbo write buffer中,当意外突出或者断电,数据库恢复数据时会先检查redo log日志文件中是否有prepare状态,如果有直接使用dubble write buffer恢复数据,如果dubble write buffer不可用则使用redo log文件恢复数据,这种方式称为二阶段提交方式。

数据写顺序:redo log ---> dubble write buffer - 通用表空间---->指定表空间

insert buffer插入缓冲

innodb使用insert buffer"欺骗"数据库:对于为非唯一索引,辅助索引的修改操作并非实时更新索引的叶子页,而是把若干对同一页面的更新缓存起来做合并为一次性更新操作,转化随机IO 为顺序IO,这样可以避免随机IO带来性能损耗,提高数据库的写性能。

插入缓冲的配置

all: 默认值,缓存insert, delete, purges操作
none: 不缓存
inserts: 缓存insert操作
deletes: 缓存delete操作
changes: 缓存insert和delete操作
purges: 缓存后台执行的物理删除操作

可以通过参数控制其使用的大小:

innodb_change_buffer_max_size,默认是25%,即缓冲池的1/4。最大可设置为50%。
当MySQL实例中有大量的修改操作时,要考虑增大innodb_change_buffer_max_size

自适应哈希索引

当缓冲池中的某个数据(17次)或者某个页(100次)经常被访问,达到一定频率的时候,Innodb会根据缓冲池中的数据自动构建一个hash索引,提高数据的访问速度,该索引称为自适应哈希索引。

Innodb存储引擎会监控对表上二级索引的查找,如果发现某二级索引被频繁访问,二级索引成为热数据,建立哈希索引可以带来速度的提升

经常访问的二级索引数据会自动被生成到hash索引里面去(最近连续被访问三次的数据),自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快。
哈希(hash)是一种非常快的等值查找方法,在一般情况下这种查找的时间复杂度为O(1),即一般仅需要一次查找就能定位数据。而B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般3-4层,故需要3-4次的查询

篇尾寄语:

技术赋能于业务,希望本篇文章让每一位读者有所收益...................................................

如有不当的地方请多多计较,共同学习,共同进步,fighting............................................

祝所有编程爱好者,求职,加薪,迎娶白富美,走向人生巅峰........................................

展开阅读全文

页面更新:2024-05-10

标签:局部性   缓存   全民   索引   原理   操作系统   内存   区域   操作   数据   空间

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top