介绍数据库中的wal技术_探究WAL日志的Logical级别
在使用PostgreSQL的逻辑复制时,需要将wal级别设置为logical,所以logical级别的wal日志一定时比replicate的wal日志多了一些数据来支持逻辑复制功能。我想很多用户或者DBA不清楚logical和replicate级别有何不同之处,这篇博客记录了logical级别相对于replicate级别多写入的wal数据,读者可以据此评估或分析改为logical级别后对wal日志
在使用PostgreSQL的逻辑复制时,需要将wal级别设置为logical,所以logical级别的wal日志一定时比replicate的wal日志多了一些数据来支持逻辑复制功能。我想很多用户或者DBA不清楚logical和replicate级别有何不同之处,这篇博客记录了logical级别相对于replicate级别多写入的wal数据,读者可以据此评估或分析改为logical级别后对wal日志膨胀的影响。
1. 逻辑复制的原理—Logical的使命
在这篇博客里详细介绍了逻辑复制的原理,这里再简单阐述一下,逻辑复制就是读取DML语句产生的wal日志,并将其解析为tuple的形式并发送到订阅端,订阅端接受到tuple之后将tuple做相应的更新处理。
比如说解析一条UPDATE语句产生的wal记录,会产生一个tuple-old和一个tuple-new,订阅端在目标表中查找与tuple-old相同的行,并把它更新为tuple-new。当然对于insert来说只有tuple-new,对于DELETE来说只有tuple-old.
所以逻辑复制的关键就是能不能从wal中解析出tuple-old和tuple-new,这也是logical级别的使命。
2. 不同Wal级别记录DML语句的方式
2.1 tuple-new的记录
FPI相关
INSERT,UPDATE或COPY语句会在数据页上插入新行。这个新行的数据一般会直接记录在这个语句产生的wal记录里。但是有一种特殊情况,如果这个wal记录同时带有FPI,那么在wal记录中会使用FPI来记录这个新行的数据,不再单独记录。
当前对wal进行逻辑解析的代码中不支持从FPI中读取具体数据(只会从独立存储的区域读取数据)。这可能是一个现有的改进点,也许原作者有更多的思考。因此为了让逻辑复制能从wal中获取到新的数据,在logical level下冗余存储了一份新数据。
UPDATE相关
在更新一条记录时,一般只会更新很少的字段。因此replicate级别下,记录tuple-new时PG更倾向于只记录更新的数据。PG的策略是跳过tuple-new前后未改变的数据。如图假设我们将一条(1,2,3,4)的行更新为(1,20,3,4),那么replicate级别下在wal中对于这个新产生的行的记录为4(20)8。其意义为20是改变的数据,20前面还有4个字节相较于tuple-old是未改动的,20后面还有8个字节相较于tuple-old是未改动的。这样的设计可以极大的减小wal的size,从而减小wal膨胀。
但是对于逻辑复制而言,它可能无法获取到old-tuple,所以无法从4(20)8这样的数据拼接出一个完整tuple-new,所以logical级别下需要改变。如下图,直接记录完整的tuple-new数据。
2.2 tuple-old的记录
replicate级别的wal日志不关心tuple-old的具体数据是什么,他只会记录这个tuple-old在数据页的位置即可。
但是在逻辑复制无法依照ctid获取tuple-old的实际数据。因此逻辑复制要求wal记录中有tuple-old的具体数据。
上图中我们可以看到在wal中记录了旧的数据,但是根据根据不同的表的配置值(NOTHING,DEFAULT,FULL,INDEX) 记录的数据的丰富程度是不一样的。
NOTHING:不记录;
DEFAULT:如果有主建记录主键,否则不记录
FULL:记录整个行数据
INDEX:记录指定索引行的数据
3. 其他
3.1 事务信息
logical级别在事务提交产生的wal日志中,增加数据库OID,数据库默认表空间OID,2PC GID,数据源信息。
3.2 TRUNCATE信息
logical级别下,会记录truncate表的wal记录
4. 总结
在这篇博客中,记录了wal的logical级别与replicate级别的不同之处,总结一下有如下几点的不同:
- 存在FPI的wal记录对新tuple的处理
- UPDATE类型的wal记录对新tuple内容记录的丰富度的不通
- 对旧tuple记录的标记的不通
- 其他不是很重要的不同之处
另外,在PG主版本的开发中目前又加入了一些其他的信息用于将长事务的数据提前发送到订阅端。
更多推荐




所有评论(0)