↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5

第 68 章 BRIN 索引

68.1. 简介 #

BRIN 是块范围索引(Block Range Index)的缩写。BRIN 旨在处理非常大的表,其中某些列与它们在表中的物理位置之间存在某种天然的相关性。

BRIN 以块范围(或“页范围”)为单位工作。块范围是表中物理上相邻的一组页;索引会为每个块范围存储一些摘要信息。例如,一个存储商店销售订单的表可能有一个日期列,表示每个订单的下单日期,而大多数情况下较早订单的条目也会较早出现在表中;一个存储邮政编码列的表,则可能会自然地把同一城市的所有邮政编码分组在一起。

BRIN 索引可以通过常规位图索引扫描来满足查询;对于每个范围,如果索引中存储的摘要信息与查询条件相一致,就会返回该范围内所有页上的全部元组。查询执行器负责重新检查这些元组,并丢弃不匹配查询条件的元组 — 换句话说,这些索引是有损的。由于 BRIN 索引非常小,与顺序扫描相比,扫描索引只会带来很小的额外开销,但可以避免扫描那些已知不包含匹配元组的大块表数据。

BRIN 索引所存储的具体数据,以及它能够满足的具体查询,取决于为该索引各列选择的操作符类。例如,具有线性排序顺序的数据类型可以使用在每个块范围内存储最小值和最大值的操作符类;几何类型则可能存储该块范围内所有对象的边界框。

块范围的大小在创建索引时由 pages_per_range 存储参数决定。索引项的数量等于该关系的页数除以为 pages_per_range 选择的值。因此,该值越小,索引就会越大(因为需要存储更多索引项),但与此同时,存储的摘要数据也会更精确,并且在索引扫描期间可以跳过更多数据块。

68.1.1. 索引维护 #

在创建索引时,会扫描所有现有堆页,并为每个范围创建一个摘要索引元组,末尾那个可能不完整的范围也包括在内。随着新页被数据填满,已经完成摘要的页范围会利用新元组中的数据更新其摘要信息。当创建了一个不属于最后一个已摘要范围的新页时,该新页所属的范围不会自动获得摘要元组;这些元组会一直保持未摘要状态,直到稍后调用摘要操作,为该范围创建初始摘要。

有几种方式可以触发页范围的初始摘要。如果对该表执行了清理,无论是手动执行还是由 autovacuum 执行,所有现有的未摘要页范围都会被摘要。另外,如果启用了索引的 autosummarize 参数(默认不启用),那么每当该数据库中运行 autovacuum 时,所有已经填满的未摘要页范围都会被摘要,而不管该表本身是否由 autovacuum 处理;见下文。

最后,还可以使用下列函数:

brin_summarize_new_values(regclass) 用于摘要所有尚未摘要的范围;
brin_summarize_range(regclass, bigint) 如果给定页所在的范围尚未摘要,则仅对该范围进行摘要。

当启用自动摘要时,一旦检测到向下一个块范围第一页的第一项执行了插入,就会向 autovacuum 发送请求,要求对前一个块范围执行定向摘要。该请求会在同一数据库中的某个 autovacuum 工作进程下一次结束运行时得到处理。如果请求队列已满,该请求就不会被记录,并会向服务器日志发送一条消息:

LOG:  request for BRIN range summarization for index "brin_wi_idx" page 128 was not recorded

发生这种情况时,该范围会保持未摘要状态,直到对该表执行下一次常规 VACUUM,或者调用上述某个函数。

反之,可以使用 brin_desummarize_range(regclass, bigint) 函数对某个范围取消摘要;当现有值已经发生变化,以致索引元组不再是良好的表示时,这会很有用。详见第 9.27.8 节。

报告文档问题

阅读 上游文档. 通过 PostgreSQL 文档反馈表单.