1、缓冲池
我们都知道,InnoDB引擎是基于磁盘存储的,但由于物理硬盘访问速度与内存访问速度存在着巨大的鸿沟,InnoDB常用缓冲池技术来提高数据库的性能。
与常用的缓存思想类似,当我们查询MySQL中的数据时,首先会访问缓冲池中的数据,如果命中缓存则直接返回,否则查询磁盘上的数据,再将数据存储在缓冲池中。对于update操作,则首先修改缓冲池中的数据而不是修改磁盘上的数据,然后再以一定频率刷新到磁盘上,这种技术叫Checkpoint,异步操作提高MySQL的整体性能。
所以缓冲池的大小严重影响MySQL的性能,通过innodb_buffer_pool_size设置缓冲池的大小(可在my.cnf中设置),查看方式为:
show variables like 'innodb_buffer_pool_size'\G;
可见,缓冲池的大小是134217728/1024/1024=128M。
2、LRU List,Free List,Flush List
缓冲池是一块很大的内存区域,其中存放很多种类型的页,页的大小默认是16k,那么innoDB是怎么管理这些页的呢?通过LRU——最近最少使用.
InnoDB在内存中维护一个缓存池用于缓存数据和索引。缓存池可以被认为一条长LRU链表,该链表又分为2个子链表,一个子链表存放old pages(里面存放的是长时间未被访问的数据页),另一个子链接存放new pages(里面存放的是最近被访问的数据页面)。
与传统的LRU算法不同,innoDB对LRU算法进行优化,插入的数据不在是在头部插入,在innoDB中引入了一个midpoint的概念,将新的数据插入到LRU List的midpoint位置处。我们可以通过命令查看midpoint的值
show variables like 'innodb_old_blocks_pct'\G;
可以看到midpoint默认值是37,表示newPage占37%,其余的是oldPage,可以通过命令调整midpoint'的值
set global innodb_old_blocks_pct=38
思考:innodb为什么要设置midpoint而不用传统的LRU算法呢?
答:这是因为若直接将读取的页放在LRU列表的首部,那么某些SQL操作可能会使缓冲池中的页被刷新出,从而影响缓冲的命中率。常见的操作如需要访问表中的很多页,也许这些页并不是热点数据,如果放在LRU列表首部,但这些页有可能会将热点数据刷出缓冲池。引入midpoint,将新查的数据存储在midpont位置中,midpoint之前的仍为最热数据。
当MySQL刚启动时,LRU List是空的,这时的页都存放在Free List中。当需要从缓冲池中分页时,首先从Free List中查找是否有空闲页,如果有则从FreeList中移除,放在LRU List中。我们可以根据以下命令查看LRU List和Free List的数据
show engine innodb status\G;
其中有几个重要的参数,我已经标红,在下面一一解释:
Buffer pool size:缓冲池中页的个数,每页默认大小16k,则缓冲池的大小是8192*16/1024=128M。
Free buffers:Free List页的个数
Database pages:LRU List页的个数
Modified db pages:脏页的个数,由于在进行update操作时首先会修改缓冲池中的数据,在定时异步的将缓冲池的数据刷新到磁盘中(checkpoint技术),所以缓冲池的数据与磁盘的数据会产生不一致,为脏页。
LRU len:LRU List的长度。
注意:脏页既存在于LRU List中,也存在Flush List中,LRU List用来管理缓冲池中可用的页,Flush List用来管理将脏页刷新到磁盘上,二者互补影响。
3、Flush List
下面我用一个例子来给大家验证Flush List和Modified db pages;
有一张user表存有如下数据:
这时我们查看Modified db pages的值为0:
当我们update的时候,我执行如下命令,修改数据并查看脏页的值,之所以连起来一起执行,是为了可以看到脏页的值的变化,如果分成两次执行,有可能checkpoint机制已将将修改的数据刷新到磁盘中而观测不到脏页的值。
update user set id=5 where id=4;show engine innodb status\G;。
|