Ⅰ、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. 【Android 应用开发】Android中的回调Callback

    回调就是外部设置一个方法给一个对象, 这个对象可以执行外部设置的方法, 通常这个方法是定义在接口中的抽象方法, 外部设置的时候直接设置这个接口对象即可. 例如给安卓添加按钮点击事件, 我们创建了OnC ...

  2. Struts源码之OgnlValueStack

    public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessVa ...

  3. 【Qt编程】基于Qt的词典开发系列<十一>系统托盘的显示

    本文主要讨论Qt中的系统托盘的设置.系统托盘想必大家都不陌生,最常用的就是QQ.系统托盘以简单.小巧的形式能让人们较快的打开软件.废话不多说,下面开始具体介绍. 首先,新建一个Qt Gui项目,类型选 ...

  4. PHP-MVC和Smarty初探笔记

    在慕课网上学习了PHP的MVC的基础知识,记录一下笔记: 等待更新~

  5. linux下由带-开头文件想到的

    如果要删除文件-aaa,使用rm -aaa是不行的,rm会认为-后面的是参数.2种办法: 1 带明确路径指示 rm ./-aaa 2 使用 -- :rm -- -aaa 因为命令如果发现参数中有--, ...

  6. rails应用ajax之一:使用纯js方法

    考虑如下需求: 1. 用户输入一个用户名,当焦点跳出文本框时,检查该用户名是否有效 2. 动态更新检查的结果 我们使用ajax的方式来实现这个简单的功能,首先建立view:check.html.erb ...

  7. JAVAEE——BOS物流项目12:角色、用户管理,使用ehcache缓存,系统菜单根据登录人展示

    1 学习计划 1.角色管理 n 添加角色功能 n 角色分页查询 2.用户管理 n 添加用户功能 n 用户分页查询 3.修改Realm中授权方法(查询数据库) 4.使用ehcache缓存权限数据 n 添 ...

  8. 点击劫持漏洞之理解 python打造一个挖掘点击劫持漏洞的脚本

    前言: 放假了,上个星期刚刚学习完点击劫持漏洞.没来的及写笔记,今天放学总结了一下 并写了一个检测点击劫持的脚本.点击劫持脚本说一下哈.= =原本是打算把网站源码 中的js也爬出来将一些防御的代码匹配 ...

  9. InnoDB的4个特性

    innodb 的四个特性 insert buffer innodb使用insert buffer"欺骗"数据库:对于为非唯一索引,辅助索引的修改操作并非实时更新索引的叶子页,而是把 ...

  10. Day12 前端html

    前端基础之HTML 老师博客: http://www.cnblogs.com/yuanchenqi/articles/6835654.html http://www.cnblogs.com/yuanc ...