Table of Contents
BRIN 是块范围索引(Block Range Index)的缩写。 BRIN 旨在处理非常大的表,其中某些列与它们在表中的物理位置之间存在某种天然的相关性。
BRIN 以 块范围 (或“页范围”)为单位工作。 块范围是表中物理上相邻的一组页;索引会为每个块范围存储一些摘要信息。 例如,一个存储商店销售订单的表可能有一个日期列,表示每个订单的下单日期,而大多数情况下较早订单的条目也会较早出现在表中; 一个存储邮政编码列的表,则可能会自然地把同一城市的所有邮政编码分组在一起。
如果索引中存储的摘要信息与查询条件相一致,BRIN 索引就可以通过常规位图索引扫描来满足查询,并返回每个范围内所有页上的全部元组。 查询执行器负责重新检查这些元组,并丢弃不匹配查询条件的元组 — 换句话说,这些索引是有损的。 由于 BRIN 索引非常小,与顺序扫描相比,扫描索引只会带来很小的额外开销, 但可以避免扫描那些已知不包含匹配元组的大块表数据。
BRIN 索引所存储的具体数据,以及它能够满足的具体查询, 取决于为该索引各列选择的操作符类。 例如,具有线性排序顺序的数据类型可以使用在每个块范围内存储最小值和最大值的操作符类; 几何类型则可能存储该块范围内所有对象的边界框。
块范围的大小在创建索引时由 pages_per_range 存储参数决定。 索引项的数量等于该关系的页数除以为 pages_per_range 选择的值。 因此,该值越小,索引就会越大(因为需要存储更多索引项), 但与此同时,存储的摘要数据也会更精确,并且在索引扫描期间可以跳过更多数据块。
在创建索引时,会扫描所有现有堆页,并为每个范围创建一个摘要索引元组,末尾那个可能不完整的范围也包括在内。 随着新页被数据填满,已经完成摘要的页范围会利用新元组中的数据更新其摘要信息。 当创建了一个不属于最后一个已摘要范围的新页时,该新页所属的范围不会自动获得摘要元组; 这些元组会一直保持未摘要状态,直到稍后调用摘要操作,为该范围创建初始摘要。
有几种方式可以触发页范围的初始摘要。 如果对该表执行了清理,无论是手动执行还是由 autovacuum 执行, 所有现有的未摘要页范围都会被摘要。 另外,如果启用了索引的 autosummarize 参数(默认不启用), 那么每当该数据库中运行 autovacuum 时,所有已经填满的未摘要页范围都会被摘要, 而不管该表本身是否由 autovacuum 处理;见下文。
最后,还可以使用下列函数(这些函数运行期间, search_path 会临时改为 pg_catalog, pg_temp):
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) 函数对某个范围取消摘要;当现有值已经发生变化,以致索引元组不再是良好表示时,这会很有用。 详见 Section 9.27.8。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。