MySQL内存
1.缓冲池
内存的作用就是存储临时数据,负责磁盘与CPU之间的数据交互。
在MySQL中,innnodb是基于磁盘存储的,由于CPU和磁盘之间的速度差别较大。
所以开辟内存,创建缓冲池,将数据暂存到缓冲池中,从而弥补CPU和磁盘之间的速度差别。
数据库实例在进行读取操作时,先将读取到的内容放在缓冲池(内存)中,然后之后再读到该内容时,判断该内容是否在内存(缓冲池)中,存在,直接从内存中读取,否则从磁盘中读取
数据库实例修改数据库时,先修改缓冲池中的数据,然后再以一定的频率刷新到磁盘上,刷新机制称为checkpoint,采用该机制是为了提高性能
一般来说,缓冲池越大,可缓冲的数据越多,数据库实例执行操作时速度越快
查看innodb缓冲池的大小
show variables like 'innodb_buffer_pool_size'\g
单位是字节
查看innodb缓冲池的个数
show variables like 'innodb_buffer_pool_instances'\g
当前innodb中,缓冲池个数为1
观察缓冲池的状态
select * from information_schema.innodb_buffer_pool_stats\G
其中Buffer pool size 8191的单位是页,一页16KB,换算为字节8192*16*1024=134217728,和之前的结果相同
innodb缓冲池的数据种类
2.LRU List, Free List,Flush List
innodb主要通过LRU List管理缓冲池,LRU(latest recently used),最频繁使用的页数据放在LRU List前部,最少使用的页数据放在LRU List尾部,
当缓冲池不能存放新的页数据时,释放LRU List尾部的页数据。页的大小默认为16K
innodb对LRU算法进行了优化,对LRU List加入了midpoint,midpoint之前的列表为new,之后的为old,new列表中的页数据都是活跃的热点数据(就是频繁被访问使用)
新读取到的页数据不直接放在LRU List的尾部,而是放在LRU List中的midpoint位置,数据页从old列表转入new列表时,称为page made young
通过innodb_old_blocks_pct 查看midpoint
show variables like 'innodb_old_blocks_pct'\g
innodb_old_blocks_pct为37,表示将新读取到的页数据放在LRU List尾部的37%的位置,即63%的活跃数据
加入midpoint的原因
如果不加midpoint,直接将数据放入LRU List的最前面,会导致最常被使用的页数据从LRU List中被剔除,而新加入的页数据并不一定是热点数据,
当再次访问被剔除的数据时,需要从磁盘中读取,速度慢
除了加入midpoint,innodb还引入了innodb_old_blocks_time,表示当访问到midpoint处的页数据时,old列表中的页数据等多久会被移到new列表中
如果该值越大,那么new列表中的页数据被刷出可能性就越小,因为innodb_old_blocks_time导致数据页没有从old列表转移到new列表的,称为not page made young
查看innodb_old_blocks_time
show variables like 'innodb_old_blocks_time'\g
修改innodb_old_blocks_time
set global innodb_old_blocks_time=500;
当数据库刚启动时,LRU List为空, 所有的内存页都在Free List中,
当有访问数据的操作时,判断Free List是否有可用空页,有则从Free List将空页删除,放入LRU List中
否则淘汰LRU List末尾的页,将内存分配给新的页
查看 LRU List 和 Free List
show engine innodb status\G
database pages表示LRU List的页数
select * from information_schema.innodb_buffer_pool_stats\G
来查询缓冲池的内存分配情况
也能通过该语句查看 page made young和 not page made young的次数
innodb缓冲池的hit rate参数
可以通过
show engine innodb status\G
查看hit rate
这个值表示缓冲池是否正常运行,一般在95%以上
如果执行上述命令时,出现No buffer pool page gets since the last printout,表示没有缓冲池内存操作,可以执行一下下面的语句
select * from sys.session\G
然后再执行show engine innodb status\G,就能查看缓冲池的命中率了
innodb缓冲池的压缩页
innode缓冲池中的页的大小一般是16K,但是页可以压缩,压缩后的大小可以是8K 4K 2K 1K,这些压缩页由unzip_LRU来管理
根据压缩页大小不同,压缩页分别由不同的unzip_LRU来管理
unzip_LRU中的页通过伙伴算法分配,分配4K的页的过程如下:
1.检查4K的unzip_LRU中是否空闲页,有,则直接使用
2.若果没有,检查8K的unzip_LRU中是否空闲页,有,将8K的unzip_LRU中分成两个4K空闲页,存放到4K的unzip_LRU中
3.若没有,从LRU中申请16K的页,分为一个8K和两个4K的,病分别存入对应的unzip_LRU中
查看unzip_LRU
show engine innodb status\G
LRU列表中包含个页,没有压缩页,LRU的的页数包括unzip_LRU的页数
也可以通过下面的语句来查询
select * from information_schema.innodb_buffer_page_lru where compressed_size<>0;
查询结果为空,与show engine innodb status\G的结果一致
innodb缓冲池的脏页
当LRU中的页被修改后,成为脏页,脏页就是缓冲池中数据和磁盘数据不一致,数据库通过checkpoint机制将脏页写入磁盘
而脏页不仅存在LRU List中,也存在于Flush list中,Flush list中的页都是脏页,只不过Flush list负责将脏页写入磁盘,而LRU List负责管理缓冲池
查看脏页
select * from information_schema.innodb_buffer_page_lru where oldest_modification!=0;
可见,脏页数为0
3.重做日志缓冲和额外内存池
除了缓冲池,LRU list Free list Flush list之外,MySQL内存结构还包括重做日志缓冲和额外内存池
重做日志缓冲的作用就是存放重做日志数据,然后以一定的频率将重做日志数据写入重做日志文件
有三种操作会将重做日志数据写入重做日志文件
1.master thread 每秒执行该操作一次
2.事物提交时
3.当重做日志缓冲的剩余空间小于总空间的一半时,会自动执行该操作
查看重做日志缓存
show variables like 'innodb_log_buffer_size';
额外内存池记录了缓冲池相关信息,当缓冲池很大时,额外内存池也对应需要加大,不是很重要
参考
《MySQL技术内幕,innodb存储引擎》
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出