PG FPI
背景
数据库页占用不少于8 KB(可能为16或32KB),在OS层面,写操作以块形式进行,通常较小(通常为512字节或4KB)。因此,在断电的情况下,可能会将部分写入数据页。在崩溃后的恢复期间,xlog 里面存储的记录变化信息不够完整,无法完全恢复该页。
FPI原理
PostgreSQL 在 checkpoint 之后在对数据页面的第一次写的时候会将整个数据页面写到 WAL 里面。当出现主机断电或者OS崩溃时,redo 操作时通过 checksum 发现“部分写”的数据页,并将 WAL 中保存的这个完整数据页覆盖当前损坏的数据页,然后再继续 redo 就可以恢复整个数据库了。
full_page_writes参数对此进行控制,并且默认情况下处于启用状态
假如要观察FPI(full-page images)的比例,我们可以使用pg_waldump -z查看占比
影响
WAL写放大:在8kB页面上更改一个字节就会将整个页面记录到WAL中,增加了WAL的大小。通常,在检查点之后会有短暂的全页写的"爆发"情况,然后在检查点结束之前会有相对较少的全页写。
什么会导致大量的FPI
-
主键列使用UUID
UUID 的话,因为无序性,随机插入,就会涉及到叶子节点的分裂与合并,导致 FPI
-
表上有 N 多个索引,那么这些索引也会导致 FPI
非HOT情况下更新,会导致堆表 FPI + 索引 FPI
详情参考:https://mp.weixin.qq.com/s/mJsAMdsETeuSKeS8E7qqrw
优化FPI
-
尽量避免使用UUID类型的字段做为主键,如果要使用,请使用有序生成的UUID
-
避免检查点太频繁的发生
全页写仅发生在检查点之后的第一次写入,因此检查减少点的频率是一种改善这种情况的方式之一。
延迟checkpoint的间隔(max_wal_size、checkpoint_timeout),但是拉长checkpoint周期实际上就是让周期内的WAL日志更多,这会导致数据库崩溃恢复的时间变长,
-
HOT
对于写负载较大的情形,其实HOT的优化效果也有限
-
wal_compression
在15的版本里新增了对FPI进行压缩的功能,Add support for LZ4 with compression of full-page writes in WAL
参考
https://mp.weixin.qq.com/s/mJsAMdsETeuSKeS8E7qqrw
https://mp.weixin.qq.com/s/pN5GvNSS_HiOMEdz2gQU3g
http://mysql.taobao.org/monthly/2015/11/05/




