文章阅读——Mysql技术内幕

第一章 mysql体系结构和存储引擎

1.1 定义数据库和实例

数据库:物理操作系统文件或其他形式文件类型的集合。

实例:MySQL数据库由后台线程和一个共享内存区构成。共享内区可以被后台运行的线程共享。数据库实例才是真正用于操作数据库文件的。实例在系统上表现为一个进程。

ps:实例与数据库通常是一一对应的,但在集群环境下可能会出现一个数据库被多个数据实例使用的情况。

 

1.2 MySQL体系结构

文章阅读——Mysql技术内幕

由图知,MySQL组成包括:

连接池组件、管理服务和工具组件、SQL接口组件、查询分析器组件、优化器组件、缓冲组件、插件式存储引擎、物理文件。

MySQL区别与其他数据库的特点:基于表的插件式存储引擎。

 

1.3 MySQL存储引擎(MySQL数据库的核心)

存储引擎的好处:每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表。

 

1.3.1 InnoDB存储引擎(MySQL默认)

InnoDB支持事务,设计目标主要是面向在线事务处理(OLTP)的应用。

特点:行锁设计,支持外键,支持全文索引(1.2版本)。默认读操作不会产生锁(一致性非锁定读)。

功能:它使用MVCC(多版本并发控制)来获得高并发性,实现了SQL的四种隔离级别,默认为REAPETABLE。使用next-keylocking的策略来避免幻读的产生。除此之外,它还提供了插入缓冲、二次写、自适应性哈希索引、预读等功能。

存储方式:聚集(clustered)的方式,每张表的存储都是按主键的顺序进行存放。若无主键,则其会为每一行生成一个6字节的ROWID,以此作为主键。

 

1.3.2 MyISAM引擎

MyISAM不支持事务、表锁设计,支持全文索引,主要面向OLAP(联机分析处理)的应用。

特点:它的缓冲池只缓存索引文件,数据文件的缓存由操作系统完成。

 

1.3.3 NDB引擎

NDB引擎是一个集群存储引擎,为share nothing的集群架构。

特点:所有的数据存放在内存中(MySQL5.1开始,可将非索引文件放在磁盘上),因此主键查找的速度极快,可通过添加NDB 数据存储节点线性地提高数据库性能。

问题:NDB存储引擎的连接(JOIN)操作是在MySQL数据库层完成的,这意味着复杂的连接操作将很慢,开销巨大。

 

1.3.4 Memory存储引擎(HEAP存储引擎)

它将表中的数据存放在内存中,适合用于存储临时数据的临时表,以及数据仓库中的纬度表。默认使用Hash索引。

缺点:只支持表锁,并发性能较差。存储varchar是是按照char来存储的,浪费空间。

 

不同存储引擎间的比较图:

文章阅读——Mysql技术内幕

 

第二章 InnoDB引擎

2.3 InnoDB体系架构

InnoDB存储池中有多个内存块,可以认为这些内存块组成了一个内存池,负责如下工作:

维护所有进程/线程需要访问的多个数据结构

缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存

重做日志(rodo log)缓冲 等等。

后台线程的作用:主要负责刷新内存池中的数据,保证缓冲池中的内存缓存是最新的;将已修改的数据文件刷新到磁盘文件中,同时保证在数据库发生异常的情况下InnoDB能够恢复到正常运行状态。

文章阅读——Mysql技术内幕

 

 

2.3.1 后台线程

InnoDB存储引擎是多线程模型,因此其后台有多个不同的线程。

1.Master Thread(核心的后台线程)

主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性。包括脏页的刷新、合并插入缓冲、UNDO页的回收等。

2.IO Thread

在InnoDB引擎中大量使用了AIO(Async IO)来处理IO请求。IO Thread的主要工作是处理这些IO请求的回调。

3.Purge Thread

事务被提交后,其所使用的undlog可能不再需要。故需要PurgeThread来回收已经分配并使用的undo页。

4.Page Cleaner Thread

在InnoDB版本1.2.x后引进。作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。目的是为了减轻原Master Thread的工作和对于用户存储线程的阻塞。

 

2.3.2 内存

1.缓冲池

是什么:缓冲池简单来说是一块内存区域,通过内存的速度弥补磁盘速度较慢对数据库性能的影响。数据库中的页的读取,是先看缓冲池中是否存在该页,若有,则直接读取;数据库中页的修改,首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。(触发机制为CheckPoint)

存储对象:文章阅读——Mysql技术内幕

从InnoDB 1.0.x版本开始,允许有多个缓冲池实例,每个页根据Hash平均分配到不同缓冲池实例中。

 

2.LRU List、Free List和Flush List

(本节解答InnoDB存储引擎如何对内存区域进行管理)

1)LRU(Latest Recent Used) List:用来管理已经读取的页。缓冲池一般使用LRU算法来进行管理。即最频繁使用的页在LRU的前端,最少使用的页在LRU的后端。当缓冲池不能存取新的页时,将首先释放LRU List的后端页。

InnoDB使用的是改良版的LRU算法,它加入了midPoint位置,还引入了innodb_old_blocks_time。

midPoint:该位置默认在LRU列表尾端的37%的位置,新读取到的页都放在这个位置。在该位置前的列表,称为new 列表,否则称为old列表。可以简单理解为,new列表中的都是最为活跃的热点数据。

使用midPoint的原因:若直接将读取到的页放入到LRU的首部,那么某些SQL操作可能会使缓冲池中的页被刷出,从而影响缓冲池的效率。常见的这类操作为索引或数的扫描操作,这类操作一般要访问很多页,但只是访问一次,并不是真正的热点数据。若直接放入LRU列表的首部,则可能会导致需要的热点数据被刷新出,下次要访问时又要在磁盘中读取,影响效率。

innodb_old_blocks_time:表示页读取到mid位置后需要等待多久才能被加入LRU列表的热端。

2)Free List:用来管理未读取的页。当数据库刚启动时,LRU List是空的,页都存放在Free List中。

LRU 与 Free List的关系:当需要从缓冲池中分页时,先从Free List中查找是否有空闲的页,有则将其从Free List中删去。否则,根据LRU算法,删去LRU尾端的页,将该内存空间分配给新的页。当页从LRU中old的部分加入到new的部分时,称为page made young;而因为innodb_old_blocks_time的设置导致页没有从old部分移动到new的部分的操作称为 page not made young。

3)压缩页的内存分配

unzip_LRU管理的是非16KB的页,LRU列表中包含了unzip_LRU的页。首先,在unzip_LRU中对不同压缩页大小的页进行分别管理。其次,通过伙伴算法进行内存的分配。

举例:现需要从缓冲池中申请页为4KB的大小,过程如下:

1)检查4KB的unzip_LRU列表,检查是否有可用的空闲页;

2)若有,则直接使用;

3)否则,检查8KB的unzip_LRU列表;

4)若能够得到空闲页,将页分成两个4KB的页,存放到4KB的unzip_LRU列表中;

5)若不能,则从LRU列表中申请一个16KB的页,分成一个8KB和两个4KB的页,分别存放进unzip_LRU列表中。

 

4)Flush List:在LRU中被修改后的页,称为脏页(dirty page)。即缓冲池中的页的数据和磁盘中的不一致。这时数据库会通过CHECKPOINT机制将脏页刷新会磁盘,Flush中存放的就是脏页列表。

PS:脏页既存在于LRU List中,也存在于 Flush List中。二者互不影响。

 

3.重做日志缓冲

在通常情况下,8MB的重做日志缓冲足以满足绝大部分的应用。因为在以下3种情况下,重做日志缓冲中的内容会刷新到外部磁盘的重做日志中:

1)Master Thread每秒会刷新一次;

2)每个事务提交后会刷新一次;

3)当redo log的空间小于1/2时,会刷新一次。

 

4.额外的内存池

在InnoDB中,对内存的管理是通过一种称为内存堆的方式进行的。在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,申请不了再从缓冲池中申请。

 

2.4 CHECKPOINT技术

1.checkpoint(检查点)技术解决的问题:

1)缩短数据库的恢复时间;

2)缓冲池不够用时,将脏页刷新到内存磁盘;

3)重做日志不可用时,刷新脏页;

2.CHECKPOINT的分类

1)Sharp Checkpoint:它发生在数据库关闭时将所有脏页刷新在磁盘。

2)Fuzzy Checkpoint:它发生在数据库运行时,它包括四种。分别是Master Thread Checkpoint、FLUSH_LRU_LIST Checkpoint、Dirty page too much Checkpoint、Async/Sync Flush Checkpoint(重做日志不可用时)

 

2.5 Master Thread 的工作方式

2.5.1 InnoDB 1.0.x版本之前的Master Thread

masterThread 具有最高的线程优先级别。

1.组成:主循环(loop)、后台循环(background loop)、刷新循环(flush loop)、暂停循环(suspend loop)。

1)loop:包括每秒的操作和每十秒的操作,由线程的sleep()控制,故这里的每秒和每十秒是不精确的。

2)background loop:当前没有用户活动或者数据库关闭时会切换到此线程。

3)flush loop:需要刷新页的时候切换到此线程。

4)suspend loop:若flush loop中也没事做,则会切换到此线程,将Master Thread 挂起。或者用户启用了InnoDB存储引擎,但是没有使用InnoDB存储引擎的表,也是此状态。

 

2.5.2 InnoDB 1.2.x版本之前的Master Thread

1.提供了参考参数innodb_io_capacity(改变硬编码带来的性能损失);

2.修改了innodb_max_dirty_pages_pct默认值为75(加快刷新脏页的频率、并且保证IO负载);

3.增加参数innodb_adaptive_flushing(自适应性刷新,该值影响每秒刷新脏页的数量);

4.引入innodb_purge_batch_size(该值控制每次full purge 时回收的Undo页的数量)

 

2.5.3 InnoDB 1.2.x版本之后的Master Thread

1.把每十秒和每秒的操作分别封装到两个函数内;

2.对于刷新脏页的操作,从Master Thread 中分离到一个单独的 Page cleaner Thread中操作,进一步提高系统的并发性。

 

2.6 InnoDB关键特性

包括插入缓冲(Insert Buffer)、两次写(Double Write)、自适应性哈希索引(Adaptive Hash Index)、异步IO(Async IO)、刷新邻接页(Flush Neighbor Page)。

 

2.6.1 插入缓冲

1.Insert Buffer

并非缓冲池的一个组成部分,而是物理页的一个组成部分。

使用场景:非唯一辅助索引的插入操作。

作用:对于非聚集索引的插入或更新操作,并非每一次都直接插入到索引页中。而是先判断插入的非聚集索引页是否在缓冲池中,入在直接插入;否则,先放到一个Insert Buffer对象中。然后再以一定的频率和情况进行Insert Buffer和辅助索引页子节点的合并操作,通常把多个插入合并为一个操作(因为在一个索引页中),则大大提高了非聚集索引插入的性能。

限制条件:1)索引是辅助(secondary)索引;2)索引不是唯一的。(看不懂这一点)

2.Change Buffer

在1.0.x版本后引入,可将其是为Insert Buffer的升级。从该版本开始,对应的DML操作)——INSERT、DELETE、UPDATE都能进行缓冲,分别是 insert buffer、delete buffer、purge buffer。

3.Insert Buffer的内部实现

内部结构:B+树,现在的版本中,全局只有一颗树,放在共享表空间(ibdatal)中。非叶节点存储的是查询的search key(键值);叶子节点存放的是对应的辅助索引页中的记录。

4.Merge Insert Buffer

可能发生Merge Insert Buffer的情况:

1)辅助索引页被读取到缓冲池中;2)Insert Buffer Bitmap 页追踪到该辅助索引页已无可用空间时;

3)Master Thread。(每秒或每十秒)

 

2.6.2 两次写

两次写带给InnoDB的是数据页的可靠性。

部分写失效:当发生数据库宕机时,可能InnoDB引擎正在写入某个页到表中,而这个页只写了一部分。例如16KB的页,只写了4KB。

double write的含义:在发生写失效时,先通过页的副本来还原页,再进行重组日志。(因为当页是损坏时,重做是无意义的。)

double write的组成(每部分均为2MB):1)内存中的double write buffer;2)磁盘上共享表空间的连续的128个页,即两个区;

                                       文章阅读——Mysql技术内幕

                                                                                 (double write 架构图)

 

2.6.3 自适应性哈希索引(AHI)

含义:InnoDB会监控对表上各索引页的查询。如果观察到建立哈希索引能够带来速度提升,则建立哈希索引。AHI是通过缓冲池的B+树页建造出来的,并不需要对全表构建。它的思想是数据库自优化

要求:1)AHI要求对这个页的连续访问模式必须是一致的,即查询的条件一样。(譬如WEHRE a = xxx)

2)以该模式访问了一百次;3)页通过该模式访问了N次,其中N=页中记录*1/16。

注意,HASH索引只能用来搜索等值查询 (即a=xxx)

 

2.6.4 异步IO(AIO)

含义:用户可以在发出一个IO请求后立即再发出另一个IO请求,当全部IO发送完毕后,等到所有IO操作的完成。不用等待一个IO操作完成后才能继续后面的操作。

优点:1)多个IO请求同时进行操作;2)可以进行IO Merge 操作,即将多个IO合并成一个IO,提高IOPS的性能。

 

2.6.5 刷新邻接页

工作原理:当刷新一个脏页时,InnoDB引擎会检查该页所在区(extent)的所有页,如果是脏页,则一起进行刷新。

好处:通过AIO可以把多个IO合并成一个IO操作,对于传统机械硬盘有很大好处(读写慢);l对于SSD则建议关闭。

 

2.7 启动、关闭和恢复

1.影响关闭的参数——innodb_fast_shutdown,该参数值可取0、1、2,默认为1。

0:表示数据库关闭时,InnoDB需完成所有的full purge 和 merge insert buffer,并将所有的脏页刷新回磁盘。

1:不需完成full purge 和 merge insert buffer。

2:上述操作都不执行,而是将日志都写入日志文件。

 

2.影响恢复的参数——innodb_force_recovery,该参数值可以是0-6,默认为0。

0:代表当发生需要恢复时,进行所有的恢复操作;当不能进行有效恢复时,把错误写入到错误日志中。

PS:当设置了大于0的参数后,用户不能对表进行DML操作。

 

第三章 文件

本章将分析构成Mysql和InnoDB存储引擎表的各种类型文件。它们包括:参数文件、日志文件、socket文件、pid文件、MySQL表结构文件、存储引擎文件。

 

3.1 参数文件

作用:告诉MySQL实例启动时可以在哪里找到数据库文件,并且指定某些初始化参数,这些参数定义了某种内存结构的大小等设置,还会介绍各种参数的类型。

与oracle的区别:oracle在没有参数文件时不能装载,而MySQL可以。但MySQL没有MySQL架构时则不可以启动(mysql.host)

 

3.1.1 什么是参数

简单来说,可以看成一个键/值对。(例如innodb_buffer_pool_size:1G)

PS:Oracle具有隐藏参数,供Oracle“内部人员”使用。SQL Server也有类似参数。(不建议使用)

 

3.1.2 参数类型

分为两类,动态参数和静态参数。

动态参数:可以在MySQL实例运行中更改。

静态参数:在整个实例生命周期内都不得进行更改。

 

3.2 日志文件

日志文件记录了MySQL数据库的各种类型活动。常见的日志文件有:错误日志、二进制日志、慢查询日志、查询日志。

 

3.2.1错误日志

该文件不仅记录了所有的错误信息,也记录一些警告信息或正确的信息。

 

3.2.2 慢查询日志

slow log 可帮助DBA定位可能存在问题的SQL语句,从而进行SQL语句层面的优化。默认为不开启。

 

3.2.3 查询日志

查询日志记录了所有对MySQL数据库请求的信息,无论这些请求是否得到了正确的执行。默认文件名为:主机名.log

 

3.2.4 二进制日志

(看不懂这里面的参数的介绍啥的)

二进制日志记录了对MySQL数据库执行更改的所有操作,但不包括SELECT 和 SHOW这类操作。(因为并没更改数据)然而,若操作本身没有导致数据库更改,该操作也可能会被写入二进制日志。默认不启动。

作用:

1)恢复:某些数据的恢复需要二进制日志。

2)复制(replication):通过复制和执行二进制日志使一台远程的MySQL数据库(一般为slave或standby)与一台MySQL数据库(一般为master或primary)进行同步。

3)审计(audit):用户可以通过二进制日志中的信息进行审计,判断是否有对数据库进行注入的攻击。

 

3.3 套接字文件

在UNIX系统下本地连接MySQL可以使用UNIX域套接字方式,这种方式需要一个套接字文件,该文件可由参数socket控制。名为mysql.sock。

 

3.4 pid文件

当MySQL实例启动时,会将自己的进程ID写入到pid文件。该文件可由参数pid_file控制,文件名为主机名.pid。

 

3.5 表结构定义文件

该文件记录了该表的表结构定义,还存放视图的定义,后缀为frm。

 

(以上均为MySQL数据库本身的文件)

 

3.6 InnoDB存储引擎文件

包括重做日志文件、表空间文件。

 

3.6.1 表空间文件