Ⅰ、double write

目的:保证数据写入的可靠性

小知识:

什么是partial write?

16k的page只写入了4k,6k,8k,12k就断掉了的情况

corrupt的page就是page的header更新了但是trailer没更新

这种page不可以通过redo log进行恢复(通过redo恢复的前提是这个page是干净的)

1.1 double write是个啥?

page更新的时候并不是直接写到对应的ibd中的而是先写入double write段对象(在共享表空间里)中,成功写满一个page再去写到磁盘(space,page_no对应位置)

但并不是每个page都这么搞一下,而是128个page搞一下(两个区),也就是2M(不可调整)

此时若发生partial write,

doublewrite里面有一个干净page的副本,可以把这个page恢复过去

如果doublewrite是partial write,那数据文件里的page没被破坏还是干净的,可以通过redo恢复

doublewrite和表空间中总有一份是干净的

弄个图看下吧:

1. 将脏页copy到Double Write Buffer对象中,默认两兆大小
2. 将Double Write Buffer中的对象先写入到共享表空间(ibdata1)
两兆循环覆盖
顺序写入(一次IO)
3. 再据(space,page_no)写入到原来的ibd文件中;
4. 如果是在写到ibdata1中的Double Write时,发宕机;此刻原来的ibd file 仍然是完整、干净的 ,下次启动后是可以用redo文件进行恢复的。
5. 如果是写到ibd文件时,发了宕机;此刻在原来的 ibdata1中存在副本 ,可以直接覆盖到ibd文件(对应的页)中去,然后再进行redo进行恢复
redo是物理逻辑的,物理表示记录的日志针对的是页(page)的修改,逻辑表示记录日志的内容是逻辑的。

1.2 性能开销

开启dw有一定的性能开销,但是不是两倍,因为是128个page才来一次,而且是顺序的写

通常5%~25%

slave服务器可考虑是否关闭?

按道理应该是没必要,slave也要保证page写入的可靠性,而且性能开销也不是很大,建议主从配置完全一致

(root@172.16.0.10) [test]> show variables like '%double%';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| innodb_doublewrite | ON |
+--------------------+-------+
1 row in set (0.01 sec)

如果你的系统不存在partial write的情况,写一个page就是原子的

就可以把这个参数关掉

磁盘:Fusion-IO

文件系统:ZFS、btrfs

--skip-doublewrite

linux中上面这两个文件系统基本是不可用的,所以不建议关闭

Ⅱ、INSERT/CHANGE BUFFER

  • 5.5版本之前叫做insert buffer,现在叫change buffer
  • 用作提高辅助索引的插入(增删改)性能
  • none unique secondary index(非唯一的二级索引)
  • insert buffer页是一棵B+ tree每次最多缓存2k的记录
  • 开启后有30%的性能提升(默认开启)

tips:

二级索引的插入是随机的(除了时间之类的),当然也不一定是二级索引,pk也一样,自增那就不存在这个问题,如果用了一个随机的函数就随机了,所以都会去做一个全局唯一的id,而且希望这个id是顺序的,因为顺序插入性能比较好,B+ tree的分裂都是朝一个方向去分裂的

2.1 Insert Buffer工作原理(空间换时间)

先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入

若不在,则先放入到一个Insert Buffer对象中(持久化的,在ibdata1中,同时会写redo日志,宕机不会出问题)

当读取辅助索引页到缓冲池,会将Insert Buffer中该页的记录合并到辅助索引页中,当然后台也有线程定期做这个从Insert Buffer中批量读取合并操作,所以,其实就是一个cache

2.2 潜在问题

①5.5之前最大可以使用1/2缓冲池内存,现在只能用1/4

(root@172.16.0.10) [zst]> show variables like '%change_buffer%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| innodb_change_buffer_max_size | 25 |
| innodb_change_buffering | all |
+-------------------------------+-------+
2 rows in set (0.01 sec)

②insert buffer开始进行合并时插入性能开始下降

shutdown不进行insert buffer记录的合并

tips:

为什么对MySQL做全插入的操作测试,结果都是一开始性能很好,慢慢越来越差 ?

开始BP是10G,一开始插入,BP都是空的,都是直接插

后面都是脏页,涉及到磁盘的读取和脏页刷回磁盘,

BP满了,也要刷盘,split

2.3 Insert/Change Buffer举例

CREATE TABLE t (
a INT AUTO_INCREMENT, -- a 列是自增的
b VARCHAR(30), -- b 列是varchar
PRIMARY KEY(a) -- a 是主键 key(b)
-- b 是二级索引(如果是name之类的,可以看成是非唯一的)
);
  • 对于a列,主键每次插入都要立即插入对应的聚集索引页(在内存中就直接插入,不在内存就先读到内存)
  • 对于b列,没有Insert Buffer,每次插入一条记录都要读取一次页(读内存,或者从磁盘读到内存),然后将记录插入到页中,若有Insert Buffer,先判断记录对应要插入的二级索引页是否在bp中,若在则直接插入,否则先cache起来放到Insert Buufer中,等二级索引页被读到,将Insert Buffer中该页对应的记录合并(Merge)进去,以此来减少io操作

小结:

综上,这是一个空间换时间(批量插入)来提升二级索引插入性能的手段,二级索引可以不急着插入,只要主键已经插入即可

2.4 查看Insert/Change Buffer

show engeine innodb status\G
...
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
Hash table size 232499, node heap has 0 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
... Seg size = size + free list len + 1 buffer中页的数量,size为used page,free list len为free page merges:合并了多少页 merged insert:插入了多少条记录 insert/merges表示插入的效率(插入一条记录,就要读取一次页) discarded operations:应该是很小的值,或者为0,当记录写入到Insert/Change Buffer后,对应的表被删除了,则相应的Buffer中的记录就应该被丢弃

使用Insert/Change Buffer的前提时,需要使用随机IO ,这时才放入Buffer中,如果页已经在Buffer Pool(内存)中,就 不需要使用Insert/Change Buffer了

2.5 change buffer

5.5之后改名为change buffer(Insert、Delete-marking、Purge)

--innodb_change_buffering
all
none
inserts
deletes
changes=(insert&delete-marking)
purges
默认all,不要动它,由它去

Ⅲ、ADAPTIVE HASH INDEX(自适应哈希索引)

3.1 搜索时间复杂度

①B+ tree O(T height),只能定位到记录所在的页

②哈希表 O(1),可以直接定位到记录

innodb自己判断这个page是不是热点page,如果是,就对page里面的记录创建ahi,这个需要的内存是向bp要的,所以不会oom

node heap has 0 buffer(s)就是问bp要的的内存,不是问操作系统要内存,顶多就是bp不够用,就不给你分配创建ahi

3.2 自适应哈希是个啥jb玩意儿?

  • 根据B+ tree的访问模式构建哈希,猜测基本没开销
  • 仅对热点page中的记录创建哈希索引
  • 非持久化
  • 仅支持点查询(point select),即等值查询

默认打开,官方5.6之后建议关闭

哈希索引的是page里面的记录,如果一个热点page,里面的记录更新很频繁,那维护ahi的代价就非常大,即使不是dml操作,仅仅select那也要创建索引

innodb_adaptive_hash_index            直接设置为off
innodb_adaptive_hash_index_parts 5.6之后推出,对ahi锁进行分片,设置为cpu的个数,当然关了之后这就不谈了

3.3 如何判断热点page?

创建ahi的过程

三个要求,很苛刻

索引是否被访问了17次?

索引中某个页已经被访问了至少100次

对索引中的页访问的模式都是相同的

idx_a_b(a,b)

where a = xxx

where a = xxx and b = xxx

没什么用,开启后性能没啥提升,却多了cpu消耗,可以跑个sysbench看看

tips:

①5.6提供了视图看访问记录数(本来都是在内存里,看不到),information_schema>INNODB_BUFFER_PAGE_LRU>FIX_COUNT

②free+lru的page数不等于总的,很大一个原因就是被ahi用了内存

Ⅳ、FLUSH NEIGHBOR PAGE(FNP)

试图刷新页所在区中的所有脏页,合并io,随机转顺序

刷一个page可能触发刷64个page,一个区里面的page是连续的,所以刷新一个区里面的page是比较顺序的,但是太狠了,出发点是好的,但是刷完马上又脏了怎么办呢?

这个特性对传统机械磁盘有效,SSD关闭此功能(随机写性能足够好了,不需要做这个随机转顺序的优化)

MySQL5.6 --innodb_flush_neighbors={1|0},默认是1,关了关了,可以在线修改的
非ssd5.7可以设置为2表示刷连续的脏页

InnoDB基本特性的更多相关文章

  1. MySQL 8.0 InnoDB新特性

    MySQL 8.0 InnoDB新特性 1.数据字典全部采用InnoDB引擎存储,支持DDL原子性.crash safe,metadata管理更完善 2.快速在线加新列(腾讯互娱DBA团队贡献) 3. ...

  2. Mysql InnoDB三大特性-- change buffer

    Mysql InnoDB三大特性-- change buffer

  3. Mysql InnoDB三大特性-- 自适应hash index

    Mysql InnoDB三大特性-- 自适应hash index

  4. Mysql --09 Innodb核心特性——事务

    目录 Innodb核心特性--事务 1.什么是事务 2.事务的通俗理解 3.事务ACID特性 4.事务流程举例 5.事务的控制语句 6.事务隐式提交情况 7.事务日志redo基本功能 8.redo数据 ...

  5. InnoDB关键特性学习笔记

    插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...

  6. 利用 Forcing InnoDB Recovery 特性解决 MySQL 重启失败的问题

    小明同学在本机上安装了 MySQL 5.7.17 配合项目进行开发,并且已经有了一部分重要数据.某天小明在开发的时候,需要出去一趟就直接把电脑关掉了,没有让 MySQL 正常关闭,重启 MySQL 的 ...

  7. innodb关键特性之double write

    # 脏页刷盘的风险 两次写的原理机制 1.解决问题 2.使用场景 3.doublewrite的工作流程 4.崩溃恢复 # doublewrite的副作用 1.监控doublewrite负载 2.关闭d ...

  8. InnoDB关键特性之刷新邻接页-异步IO

    Flush neighbor page 1.工作原理 2.参数控制 AIO 1.开启异步IO 一.刷新邻接页功能 1.工作原理 当刷新一个脏页时,innodb存储引擎会检测该页所在区(extent)的 ...

  9. Mysql InnoDB三大特性-- double write

    转自:http://www.ywnds.com/?p=8334 一.经典Partial page write问题? 介绍double write之前我们有必要了解partial page write( ...

随机推荐

  1. 分布式版本库——Windows下Git的环境部署以及在GitHub上开源自己的项目

    分布式版本库--Windows下Git的环境部署以及在GitHub上开源自己的项目 这几天着实忙的焦头烂额,可惜不是搞技术,今天周日,难得闲下来,写篇大家都想学习的Git教程,其实廖雪峰老师的网站已经 ...

  2. 介绍一种很棒的wince 如何替换系统声音的方法

    Topic:介绍一种很棒的wince 如何替换系统声音的方法(作者:Baiduluckyboy) //------------------------------------------------- ...

  3. 如何利用c中的指针实现两个8bit的数合并为16bit

    对于从事单片机开发,进行单片机c语言开发的人来说,在对外部信息采集回来的数据进行处理,经常会用到,将采集到的第一个字节作为高8位,采集到的第二个字节作为低8位,从而构成1个16bit的数,得到一次完整 ...

  4. golang实现文字云算法

    golang实现文字云算法 项目链接 https://github.com/bangbaoshi/wordcloud 效果图 测试步骤如下 git clone https://github.com/b ...

  5. 超强js博客值得学习!!!

    再读ecmascript 摘要: 这几天,又花了点时间看了下ecmascript.以下是我摘录出来的一些理解.在此记录下.第一部分:关于变量对象的理解1) 什么是变量对象?数据的存取与读取机制,就是变 ...

  6. FFPLAY的原理(三)

    播放声音 现在我们要来播放声音.SDL也为我们准备了输出声音的方法.函数SDL_OpenAudio()本身就是用来打开声音设备的.它使用一个叫做SDL_AudioSpec结构体作为参数,这个结构体中包 ...

  7. php实现点击文字提交表单并传递数据至下一个页面

    <?php $id="4";//等会要把这个数据传到第二个页面 ?> <?php echo "<li>"; echo " ...

  8. 神奇的ASCⅡ码图

    神奇的ASCⅡ码图 可能在网上也常见了asc2码图,但你知道是怎么做出来的吗?(总不可能是人一个一个字码进去的吧,当然,不排除有这种神人的可能

  9. ThinkPHP5从零基础搭建CMS系统(二)

    接上节,开启wamp集成环境,在浏览器地址栏输入http://localhost/cms/public,即可运行项目,但是这边域名太长,做一下处理. 注:需要查看tp5全部教程,请点击右侧thinkp ...

  10. java线程之线程通信控制

    在上篇我们看到,A线程往公共资源库(对象)提供了一条数据,然后B线程从库中提取了数据并打印出来. 实际项目中,我们不可能只往库中提供一条数据,而且库的大小也不会是无穷大的,那么我们就会有这样一 个需求 ...