对于扫表的查询,buffer区该如何应对?
1.如果没有额外的处理会如何
例如扫描表tableA
select * from tableA;
当tableA有许多页面,查询会将tableA的页面加载到buffer区中,那么就会将buffer区大量甚至全部的页面淘汰了。这个就不是我们希望看到的,前面我们按照 clock sweep的NFU算法,将频繁访问的页面留在内存中,然后一次扫表查询,就把buffer高频访问的页面淘汰,相当不划算。
2.解决方式
对于扫表的查询,限定查询使用的buffer数量。例如一次扫表查询,限定使用20个buffer,后续加载第21个页面时,也在这20个buffer进行淘汰。
在PG代码中,提出了ring buffer,
除了扫表查询(Bulk-READ),还有批量写(Bulk-writing)、vacumm机制需要ring buffer
3.具体实现
在PG中,获取buffer,分成两种有策略情况和普通情况
有策略情况,对应这对于扫表查询、批量写这样的情况,需要分配一个ring buffer,buffer的分配需要在ring buffer内进行分配。(可能这叫策略吧)
普通情况就是正常的随机访问,buffer的分配就是在buffer池进行分配
typedef enum BufferAccessStrategyType { BAS_NORMAL, /* Normal random access */ BAS_BULKREAD, /* Large read-only scan (hint bit updates are * ok) */ BAS_BULKWRITE, /* Large multi-block write (e.g. COPY IN) */ BAS_VACUUM /* VACUUM */ } BufferAccessStrategyType;
BufferAlloc:分配一个buffer,其中新分配时会调用到 StrategyGetBuffer
StrategyGetBuffer:入参strategy,传入对应的策略,普通情况时就是null;
typedef struct BufferAccessStrategyData *BufferAccessStrategy; typedef struct BufferAccessStrategyData { BufferAccessStrategyType btype; int nbuffers; int current; Buffer buffers[FLEXIBLE_ARRAY_MEMBER]; } BufferAccessStrategyData;
这里提出一个思考,ring buffer是单独划分的吗,独立于 buffer pool吗?
buffer pool指的公共的buffer池,在PG中就是BufferBlocks
答案:ring buffer还是在buffer pool内,可以看AddBufferToRing