innodb引擎四大特性

预读(read ahead)

缓冲池

缓存表数据与索引数据,把磁盘上的数据加载到缓冲池,避免每次访问都进行磁盘IO,起到加速访问的作用.

同步

对于数据库中页修改的操作,则首先修改缓冲池中的页,并写到redo log中,然后以checkpoint机制刷新回磁盘上,进一步提高了数据库的性能

预读

数据库访问通常都遵循集中读取原则,使用一些数据大概率会使用附近的数据,这就是所谓的局部性原理,它表明提前加载是有效的,能减少磁盘的i/o

预读机制就是发起一个i/o请求,异步的在缓冲池中预先回迁若干个页面,预计将会用到的页面回迁.

innodb16kb一页,以64个页为一个extent,那么InnoDB的预读是以page为单位还是以extent?

img

​ 数据库请求数据的时候,会将读取请求交给文件系统,放入请求队列中;相关进程从请求队列中将读请求取出,根据需求到相关数据区(内存,磁盘)读取数据;读取的数据,放入响应队列中,最后数据库就会从响应队列中将数据去走,完成一次数据读操作过程

​ 接着进程继续处理请求队列,(如果数据库是全表扫描的话,数据读请求将会占满请求队列),判断后面几个数据请求的数据是否相邻,再根据自身系统IO带宽处理量,进行预读,进行读请求的合并处理,一次性读取多块数据放入响应队列中,再被数据库取走.

innodb使用俩种读取算法来提高i/o性能:线性预读(linear read-ahead)和随机预读(randomread-ahead)

为了区分这俩种预读方式,我们可以吧线性预读放到extent为单位,而随机预读放到extent中的page为单位.线性预读着眼将下一个extent提前读取到buffer pool中,而随机预读着眼于将当前extent中的剩余page提前预读到buffer pool中

线性预读(linear read-ahead)

线性预读方式有一个很重要的变量控制是否将下一个extent预读到buffer pool中,通过使用配置参数innodb_read_ahead_threshold,控制出发innodb执行预读操作的时间.

如果一个extend中的被顺序读取的页超过或者等于该变量时,innodb将会异步的下一个extent读取到buffer pool中,innodb_read_ahead_threshold可以设置0-64的任何值(约为extent中也就只有64页)默认值为56,值越高,访问模式检查越严格.

随机预读(randomread-ahead)

这种预读发生在一个数据也成功读取buffer pool的时候

当同一个extent中的一些page在buffer pool中发现时,innodb会将该extent中剩余的page一并读到buffer pool中

mysql> show variables like 'innodb_random_read_ahead';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_random_read_ahead | OFF   |
+--------------------------+-------+

由于随机1预读方式给innodb code带来了不必要的复杂性,同时存在性能的不稳定,在5.5中已经将这种预读方式废弃,默认是off,若要启用此功能,即将配置变量设置innodb_random_read_ahead为ON。

这里有个问题,首先数量是多少,默认情况下,是13个数据页.

写缓冲(change buffer)

在MySQL5.5之前,叫插入缓冲(insert buffer),只针对insert做了优化;现在对delete和update也有效,叫做写缓冲(change buffer)。

它是一种应用在非唯一普通索引页(non-unique secondary index page)不在缓冲池中,对页进行了写操作,并不会立刻将磁盘页加载到缓冲池,而仅仅记录缓冲变更(buffer changes),等未来数据被读取时,再将数据合并(merge)恢复到缓冲池中的技术。写缓冲的目的是降低写操作的磁盘IO,提升数据库性能。

https://www.nasuiyile.cn/209.html这里有详细的介绍

二次写(double wirte)

脏页刷盘风险

关于IO的最小单位

mysql最小的io单位是16k,oracle是8k

文件系统io最小的单位是4k(不同的文件系统不一样,也有1k的)

因此存在IO写入导致page损坏的风险

img

double write俩次写

提高innodb的可靠性1,用来解决部分写失败(partial page write页断裂)

解决的问题

一个数据页的大小是16k,假设在把内存中的脏页写到数据库的时候,写了2k突然掉电,也就是说前2k数据是新的,后14k是旧的,那么磁盘数据库这个数据页就是不完整的,是一个坏掉的数据页.redo只能加上旧,校验完整的数据页恢复一个脏块,不能修复坏掉的数据页,所以这个数据就丢失了,可能会造成数据的不一致,所以需要double write.

使用场景

当数据库正在从内存向磁盘写一个数据页时,数据库宕机,从而导致了这个页只写了部分数据,这就是部分写失效,它会导致数据丢失.这时是无法通过重做日志恢复的,业务重日志记录的只能是页的物理修改,如果页本身已经损坏,重做日志也无能为力.

double wirte工作流程

img

double write由俩部分组成,一部分为内存中的double write buffer,其大小为2mb,另一部分是磁盘上共享表空间(idata X)中连续的128个页,即俩个区(exent),大小也就是2m

  • 当一些列机制出发数据缓冲池中的脏页刷新时,并不直接写入磁盘数据文件中,显示拷贝到内存中的double write buufer中
  • 接着从俩次写入缓冲区分俩次写入磁盘共享表空间中(连续存储,顺序写,性能很高),每次写1mb;
  • 待第二部完成后,再将doublewritebuffer中的脏页数据1写入实际的各个表空间文件(离散写);(脏页数据固话后,即进行标记对于doblewrite数据可覆盖)

doublewirte的崩溃恢复

如果操作系统在将页写入磁盘的过程中发生崩溃,在恢复过程中,innodb存储引擎可以从共享表的空间的doblewrite中找到该页的一个最近副本,将其复制到表空间文件,在应用redo log,就完成了恢复过程.

因为有副本所以担心表空间中数据是否损坏

为什么写日志不需要doublewrite的支持

因为redolog写入的单位就是512字节,也就是磁盘io的最小单位,所以无所谓数据损

副作用

double write带来的写负担

double write是一个buffer,但其实他是在物理文件上的一个buufer,其实也就是file,所以会导致系统有更多的fsync操作,而磁盘的fsync性能是很慢的,所以会降低mysql的整体性能

但时doublewrite buffer写入磁盘共享表达空间这个过程是连续存储,是顺序写,性能非常高1,牺牲这一点来抱枕该数据也的完整性还是很有必要的

关闭double write适合的场景

海量的增删改

不惧怕系统数据损坏和丢失

系统写负载为主要负载

总结

作为innodb的一个关键特性,doublewrite给你1默认是开启的,但是在上述特殊情况场景也可以关闭,来提高数据库写性能,配置文件修改重启数据库

查看

mysql> show variables like '%double%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| innodb_doublewrite | ON    |
+--------------------+-------+
1 row in set (0.04 sec)

为什么没有吧double里面的数据写到data page里面呢

  • doublewrite里面的数据是连续的,如果直接写到data page里面,而datapage的页又是离散的,写入会很慢
  • double write里面的数据没有办法被及时的覆盖掉,导致double write的压力很大;短时间内可能会出现double write溢出的情况。

转载自https://www.cnblogs.com/geaozhang/p/7241744.html

自适应哈希(ahi)

索引的资源消耗分析

三大特点

  • 小:值在一个到多个列建立索引
  • 有序:可以快速定位终点
  • b+树,可以定位起点,树豪赌一般小于等于3

消耗点

  • 树的高度,顺序访问索引的数据页,索引就是在列上建立的,数据量非常小,在内存中
  • 数据之间跳着访问

    • 索引往表上跳,可能需要访问表的数据页很多
    • 通过索引访问表,主键列和索引的有序度出现严重不一致时,可能就会产生大量物理读

最厉害的消耗:通过索引访问多行,需要从表中取多行数据,如果无序的话,来回跳着找,跳着访问,物理读会很严重

自适应哈希

原理过程

img

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

在使用hash索引1功能默认是打开的

mysql> show variables like '%ap%hash_index';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_adaptive_hash_index | ON    |
+----------------------------+-------+
1 row in set (0.01 sec)

进程访问的二级索引会自动被生成的到hash索引里面去(最近连续被访问三次的数据),自适应哈希通过缓冲池的b+树构造而来,因此建立的速度回很快

特点

  • 无序,没有树高
  • 降低对二级索引树的频繁访问资源
  • 自适应

缺陷

  • hash自适应索引会占用innodb buffer pool;
  • 自适应hash索引值适合搜索等值查询,如select * from table where index_col='xxx',而对于其他查找类型,如范围查找,是不能使用的;
  • 极端情况下,自适应hash索引才有比较大的意义

限制

  • 只能用于等值比较,0例如=,<=,>=,in
  • 无法用于排序
  • 有冲突的可能
  • mysql自动管理,无法人为干预

控制

由于innodb不支持hash索引,但是在某些情况下hash索引的效率很高,于是出现了adaptive hash index功能,但是通过上面的状态监控,可以计算其收益以及付出,控制该功能开启与否。

可以通过 set global innodb_adaptive_hash_index=off/on 关闭和打开该功能。

转载自:https://www.cnblogs.com/geaozhang/p/7252389.html

Last modification:November 17, 2023
如果觉得我的文章对你有用,请随意赞赏