【Mysql】InnoDB存储引擎 柔情只为你懂 2021-11-23 03:14 322阅读 0赞 作为后端开发,一直对经常打交道的Mysql的存储引擎和底层实现不熟悉,看了[MySQL技术内幕-InnoDB存储引擎][MySQL_-InnoDB]一书,有了一些初步认识,总结一些关键要点与大家分享。 ## 1 InnoDB体系架构 ## ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxNjY1MDEx_size_16_color_FFFFFF_t_70][] InnoDB存储引擎有多个内存块组成了一个大的内存池,负责维护进程/线程访问的数据结构,缓存磁盘数据,重做日志(redo log)缓冲等。后台进程负责刷新内存池数据,保证最新,数据库异常时能恢复到正常运行状态。 ### 1-1 后台线程 ### 1. **Master Thread** 核心后台进程,负责将缓冲池数据异步刷新到磁盘,保证数据一致,包括脏页刷新,合并插入缓存,UNDO页回收。 2. **IO Thread** 使用AIO(Async IO)处理IO请求,分别有wirte、read、insert buffer和log IO Thread 3. **Purge Thread** 事务提交后,undolog可能不再需要,Purge Thread 回收已经使用并分配的undolog 4. **Page clean Thread** 脏页刷新工作放入单独的线程完成,减轻Master工作 ### 1-2 内存结构 ### ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxNjY1MDEx_size_16_color_FFFFFF_t_70 1][] 1. **重做日志缓冲(redo log buffer)** 先将重做日志信息放入这个缓冲区,然后按频率刷新到重做日志文件,默认有8M大小。触发情况有三种:Master Thread每一秒将重做日志缓冲刷新到重做日志文件;每个事物提交;重做缓冲池剩余空间小于二分之一。 2. **额外内存池** InnoDB中对内存管理是通过内存堆的方式进行的。在对一些数据结构本身的内存进行分配时,需要额外从内存池中申请,当该区域内存不够用时,会从缓冲池中申请。例如分配了缓冲池,但没个缓存池中的帧缓存和对应缓冲控制对象(这些对象记录了一些LRU、锁、等待等信息)需要从额外内存池中申请。 3. **插入缓冲(insert buffer)** InnoDB存储引擎中,主键是唯一标识符。通常行记录插入顺序是按照主键递增的顺序插入的,因此聚集索引(Primary Key)一般是顺序的,不需要磁盘的随机读取,速度非常快。对于非聚集不唯一的索引,进行插入操作时,数据页存放还是按照主键顺序存放,但对于非聚集索引叶子节点插入不再是顺序的,需要离散的访问非聚集索引页(B+树),随机读取存在导致插入速度下降。 InnoDB开创性设计了Insert Buffer,对于非聚集索引插入/更新,不是每一次直接插入到索引页。而是先判断要插入的非聚集索引页是否在缓存池中,若在直接插入,不在放入一个Insert buffer对象中,然后以一定频率和情况进行Insert Buffer和辅助索引叶子节点merge(合并)操作,通常能将多个操作合并到一个操作中。 Change Buffer是对insert buffer的升级,可以对DML操作都进行缓冲。其内部实现数据结构也是一棵B+树。 4. **自适应哈希(AHI)** InnoDB存储引擎会监控对表上索引页的查询。如观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引。AHI通过缓冲池的B+树页构造而来,因此建立速度很快,不需要对整张表结构建哈希索引。AHI有一个要求,对这个页的连续访问模式必须是一样的。 5. **锁信息** InnoDB存储引擎提供一致性的非锁定读,行级锁的支持。latch是轻量级的锁,锁定时间非常短,分为互斥量和读写锁。lock的对象是事务,用来锁定表、页和行,有死锁机制,分为行锁,表锁,意向锁。 6. **LRU List、Free List 和 Flush List** LRU List:数据库中的缓冲池是通过LRU算法管理的,缓冲池中的页默认16KB,InnoDB对传统LRU做了优化,加入了midpoint位置,参数innodb\_old\_blocks\_pct控制,默认在5/8处,新读取到的页并不放在LRU列表的首部,而是midpoint位置。midpoint之前称为new列表,之后称为old列表。另外引入innodb\_old\_blocks\_time设置读取到mid位置后多久加入到LRU列表的热端。目的是为了防止某些SQL操作(数据或索引扫描)把缓冲池中的页刷出,从而影响效率。 Free List:数据库刚启动时,LRU列表是空的,页都存放在Free列表页。当需要从缓冲池分页时,首先从Free列表中查找时候有可用的空闲页,有将该页从Free列表删除,放入LRU列表,若无根据LRU算法,淘汰LRU列表末尾的页。 Flush List:LRU列表页被修改后,称为脏页,即缓冲池和磁盘不一致。数据库会通过CHECKPOINT机制将脏页刷回磁盘,Flush列表中的页即为脏页列表。脏页既存在LRU列表也存在Flush列表中。 ### 1-3 日志系统 ### 参考:[redo log、binlog、undo log 区别与作用][redo log_binlog_undo log] ### 1-4 存储引擎索引 ### InnoDB支持以下几种常见的索引 * B+树索引 * 全文索引 * 哈希索引 [MySQL_-InnoDB]: https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=MySQL%E6%8A%80%E6%9C%AF%E5%86%85%E5%B9%95-InnoDB%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E&rsv_pq=b3d9fdad0004bc0c&rsv_t=bd991FuVGTZ4R73sUqfGYMC%2F8AUAUUdUH4C%2BNiPUDeuB1pGTWScUBbt7aMQ&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=2&rsv_sug1=2&rsv_sug7=101&rsv_n=2&rsv_sug2=0&inputT=11615&rsv_sug4=11615 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxNjY1MDEx_size_16_color_FFFFFF_t_70]: /images/20211122/fb830fb3a3834b00ae908372bded0a4c.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxNjY1MDEx_size_16_color_FFFFFF_t_70 1]: /images/20211122/3349aa3dd049429b8c1ee0c93b7eb4be.png [redo log_binlog_undo log]: https://blog.csdn.net/u010002184/article/details/88526708
还没有评论,来说两句吧...