diff --git a/mysql/mysql文档/innodb体系结构.md b/mysql/mysql文档/innodb体系结构.md index 308585b..e107e0a 100644 --- a/mysql/mysql文档/innodb体系结构.md +++ b/mysql/mysql文档/innodb体系结构.md @@ -1,3 +1,87 @@ +- [innodb体系结构](#innodb体系结构) + - [innodb体系结构](#innodb体系结构-1) + - [mysql存储结构](#mysql存储结构) + - [内存结构](#内存结构) + - [Buffer Pool](#buffer-pool) + - [change Buffer](#change-buffer) + - [Adaptive hash index](#adaptive-hash-index) + - [log Buffer](#log-buffer) + - [磁盘存储结构](#磁盘存储结构) + - [system tablespace](#system-tablespace) + - [后台线程](#后台线程) + - [Master Thread](#master-thread) + - [IO Thread](#io-thread) + - [Purge Thread](#purge-thread) + - [Page Cleaner Thread](#page-cleaner-thread) + - [内存](#内存) + - [缓冲池](#缓冲池) + - [缓冲池参数配置](#缓冲池参数配置) + - [innodb\_buffer\_pool\_size](#innodb_buffer_pool_size) + - [LRU List, Free List, Flush List](#lru-list-free-list-flush-list) + - [midpoint](#midpoint) + - [page made young](#page-made-young) + - [youngs/s \& non-youngs/s](#youngss--non-youngss) + - [buffer pool hit rate](#buffer-pool-hit-rate) + - [FreeList](#freelist) + - [Flush List](#flush-list) + - [redo log buffer](#redo-log-buffer) + - [checkpoint](#checkpoint) + - [缩短数据库恢复时间](#缩短数据库恢复时间) + - [缓冲池不够用](#缓冲池不够用) + - [redo log不可用](#redo-log不可用) + - [LSN](#lsn) + - [Fuzzy Checkpoint](#fuzzy-checkpoint) + - [checkpoint种类](#checkpoint种类) + - [Master Thread Checkpoint](#master-thread-checkpoint) + - [FLUSH\_LRU\_LIST\_CHECKPOINT](#flush_lru_list_checkpoint) + - [Async/Sync Flush Checkpoint](#asyncsync-flush-checkpoint) + - [Dirty Page too Much](#dirty-page-too-much) + - [Buffer pool刷新](#buffer-pool刷新) + - [innodb\_max\_dirty\_pages\_pct\_lwm](#innodb_max_dirty_pages_pct_lwm) + - [innodb\_lru\_scan\_depth](#innodb_lru_scan_depth) + - [自适应刷新](#自适应刷新) + - [innodb\_adaptive\_flushing\_lwm](#innodb_adaptive_flushing_lwm) + - [innodb\_adaptive\_flushing](#innodb_adaptive_flushing) + - [Log Buffer](#log-buffer-1) + - [innodb\_flush\_log\_at\_trx\_commit](#innodb_flush_log_at_trx_commit) + - [innodb\_flush\_log\_at\_timeout](#innodb_flush_log_at_timeout) + - [Master Thread](#master-thread-1) + - [每秒钟执行一次的操作](#每秒钟执行一次的操作) + - [每10秒执行的操作](#每10秒执行的操作) + - [change buffer](#change-buffer-1) + - [聚簇索引和辅助索引插入顺序](#聚簇索引和辅助索引插入顺序) + - [change buffer配置](#change-buffer配置) + - [优势](#优势) + - [弊端](#弊端) + - [`innodb_change_buffering`](#innodb_change_buffering) + - [`innodb_change_buffer_max_size`](#innodb_change_buffer_max_size) + - [double write](#double-write) + - [double write结构](#double-write结构) + - [innodb\_doublewrite](#innodb_doublewrite) + - [DETECT\_AND\_RECOVERY](#detect_and_recovery) + - [DETECT\_ONLY](#detect_only) + - [innodb\_doublewrite\_dir](#innodb_doublewrite_dir) + - [innodb\_doublewrite\_pages](#innodb_doublewrite_pages) + - [innodb\_doublewrite\_files](#innodb_doublewrite_files) + - [flush list dobulewrite file](#flush-list-dobulewrite-file) + - [lru doublewrite file](#lru-doublewrite-file) + - [adaptive hash index(自适应哈希)](#adaptive-hash-index自适应哈希) + - [自适应哈希](#自适应哈希) + - [自适应哈希构建](#自适应哈希构建) + - [访问模式](#访问模式) + - [AHI构建要求](#ahi构建要求) + - [non-hash searches](#non-hash-searches) + - [innodb\_adaptive\_hash\_index](#innodb_adaptive_hash_index) + - [异步io](#异步io) + - [Sync IO](#sync-io) + - [AIO](#aio) + - [io merge](#io-merge) + - [刷新邻接页](#刷新邻接页) + - [启动、关闭和恢复](#启动关闭和恢复) + - [innodb\_fast\_shutdown](#innodb_fast_shutdown) + - [innodb\_force\_recovery](#innodb_force_recovery) + + # innodb体系结构 ## innodb体系结构 innodb体系结构由如下部分构成 @@ -498,6 +582,108 @@ doublewirte file命名格式如下所示: #ib_page_size_file_number.dblwr ``` +## adaptive hash index(自适应哈希) +自适应哈希允许innodb在不牺牲传统食物特性以及可靠性的基础上,在工作负载适当,buffer pool内存充足的场景下,表现的更像in-memory database。 + +### 自适应哈希 +哈希的查找性能较B+树来说较高,B+树的查找次数取决于B+树的高度,生产环境中B+树的高度通常为3~4层,故而需要3~4次查询,而哈希通常只需要一次查找就能定位到数据。 + +#### 自适应哈希构建 +innodb监控索引查询,并且当观测到建立哈希索引能够加速查询时,会自动创建哈希索引,故而成为自适应哈希索引(AHI)。 + +AHI是通过buffer pool中的`B+树页`来构建的,故而构建数度很快。`AHI并不需要根据整张表构建哈希索引`,innodb会根据访问频率和模式来自动为某些热点页建立哈希索引。 + +#### 访问模式 +AHI在监控索引访问时,要求页的连续访问模式必须是一样的。例如,对于`(a,b)`这样的联合索引页,其访问模式存在如下可能场景: +- where a = xxx +- where a = xxx and b = xxx + +上面两种场景都会走`(a,b)`联合索引,但是在AHI看来其访问模式并不相同。 + +#### AHI构建要求 +在满足对索引页的连续访问模式一样后,AHI的构建还有如下要求: +- 以相同模式访问了100次 +- 待构建的索引页通过该模式访问了N次,`N = 页中的记录数 / 16` + +即对于制定索引,既要求访问该索引的条件相同,也要求索引页被多次访问(索引页被访问次数达到页中记录数的1/16) + +在启用AHI后,读取和写入速度可以提升2~3倍,辅助索引连接性能可以提升5倍。 + +#### non-hash searches +hash索引只能被用于等值查询,对于其他类型查找,例如范围查找并不适用。 + +### innodb_adaptive_hash_index +是否启用自适应哈希索引可以通过`innodb_adaptive_hash_index`变量来控制,当值为`ON`时,代表自适应哈希索引被启用。 + +hash index是通过index key的前缀来进行构建的,prefix可以是任何长度,并且只有b树中的一些值能够出现在hash index中。`hash index是为经常被访问的索引页面按需进行构建的`。 + +如果一张表几乎全部都加载到了内存中,那么通过hash index能够加速对该表的查询。此时,hash index对应的value类似于指针,能够直接访问表中的任何元素。 + +> innodb中存在监控索引搜索的机制,如果innodb发现可以通过构建hash index来受益,那么其会字段能够构建hash索引。 + +在某些工作负载下,hash index带来的查找加速远远超过了`监控索引搜索`以及`维护hash index结构`带来的开销。 + +但是,在某些高工作负载的场景下,hash index可能并不会带来收益,此时,可以关闭hash index从而减少额外开销。 + +adaptive hash index是被分区的,每个hash index被绑定到一个分区,并且每个分区被一个独立的latch保护。 + +分区数量可以通过`innodb_adaptive_hash_index_parts`来控制,默认为8,最大可以设置为512. + +可以通过`show engine innodb status`中输出的` SEMAPHORES`部分来监控adaptive hash index。如果存在许多线程正在等待`btr0sea.c`中创建的rw latches,可以考虑增加adaptive hash index partitions或者禁用adaptive hash index。 + +## 异步io +为了提升数据库性能,innodb采用异步io操作方式。 + +### Sync IO +传统的Sync IO要求每进行一次io操作,都要求当前io操作执行完成后才能执行下一次io操作。 + +对于同步阻塞io,当用户发送了一条索引扫描的查询指令时,那么该sql可能需要扫描多个索引页面,每次索引页面的扫描需要一次IO操作。sync io需要每次索引扫描完成后再执行下一次索引扫描。 + +### AIO +对于异步io,用户可以在发送一个io指令后立刻再发送另一个io指令,并在所有io指令发送后等待所有io操作完成。发送另一个io指令时,并不需要等待前面io操作的完成,这样可以降低在io阻塞上等待的时间。 + +#### io merge +aio除了可以无阻塞的执行多条io操作外,还可以进行io merge操作,即将多个io合并为一个io。通过将多个io请求合并为一个io请求,可以提升iops(每秒钟执行的io数量)。 + +例如,用户需要访问的页(space, page)为`(8,6), (8,7), (8,8)`,每个页的大小为16kb,那么当使用同步io时,需要执行3次io操作。 + +当时,当使用aio时,aio会判断`(8,6), (8, 7), (8,8)`这是那个页是连续的,那么aio底层只会发送一个io请求,从(8,6)开始,读取48KB大小的数据。 + +通过linux命令`iostat`,能够观察`rrqm/s`和`wrqm/s`(read/write requests merged per second)。 + +## 刷新邻接页 +innodb中提供了刷新邻接页的特性。当刷新脏页时,innodb会检测页所在区(extent)中的所有页,如果也是脏页,则会一起执行刷新操作。 + +通过刷新邻接页的操作,可能将不怎么脏的脏页也进行了刷新,而该页和快又被变脏;而且,在使用固态硬盘时,固态硬盘拥有较高的iops,可能并不太需要该特性。 + +可以通过`innodb_flush_neighbors`变量来控制是否刷新邻接页。 + +## 启动、关闭和恢复 +### innodb_fast_shutdown +在innodb进行关闭时,`innodb_fast_shutdown`参数影响innodb引擎的行为,该参数可选值为`0,1,2`,默认值为1。 + +参数各值代表的行为如下: +- 0: mysql数据库关闭时,innodb需要完成所有full purge和merge insert buffer,并且要将所有的脏页刷新到磁盘中。这需要很长时间来完成,`如果在对innodb进行升级时,需要将这个参数调整为0,并关闭数据库` +- 1: 默认值,代表不需要完成full purge和merge insert buffer操作,但是要将脏页刷新会磁盘 +- 2: 代表不完成full purge和merge insert操作,也不将脏页刷新回磁盘,而是将日志都写到日志文件中,这样不会有任何事物的丢失,但是下次mysql启动时,需要执行恢复操作(recovery) + +### innodb_force_recovery +参数innodb_force_recovery控制innodb引擎的恢复情况。该参数默认为0,代表需要恢复时进行所有恢复操作;并且当不能有效恢复时,例如数据页发生冲突,会令mysql宕机,并且将错误写入到错误日志中。 + +innodb_force_recovery的取值如下: +- 0:默认 +- 1(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的冲突页 +- 2(SRV_FORCE_NO_BACKGROUND):阻止master thread线程的运行,如master thead需要进行full purge,这会导致crash +- 3(SRV_FORCE_NO_TRX_UNDO):不进行事务的回滚 +- 4(SRV_FORCE_NO_IBUF_MERGE):不进行插入缓冲的合并操作 +- 5(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看undo log,innodb会将未提交事务看作已提交 +- 6(SRV_FORCE_NO_LOG_REDO):innodb不执行前滚操作 + +> 如果在数据库发生宕机时,存在未提交事务,那么将下次数据库启动时,会先根据未提交事务的undo log来对数据进行回滚。 + + + +