BRIN表示块范围索引。 BRIN是为处理这样的表而设计的:表的规模非常大,并且其中某些列与它们在表中的物理位置存在某种自然关联。一个块范围是一组在表中物理上相邻的页面,对于每一个块范围在 索引中存储了一些摘要信息。例如,一个存储商店销售订单的表可能有一个日期 列记录每个订单产生的时间,并且很多时候较早的订单项也将出现在表中较早的 地方。一个存储 ZIP 代码列的表中一个城市的所有代码可能自然地聚在一起。
如果索引中存储的摘要信息与查询条件一致,BRIN 索引可以通过常规的位图索引扫描满足查询,并且将会返回每个范围中所有页面 中的所有元组。查询执行器负责再次检查这些元组并且抛弃掉那些不匹配查询条 件的元组 — 换句话说,这些索引是有损的。由于一个BRIN 索引很小,扫描这种索引虽然比使用顺序扫描多出了一点点开销,但是可能会避 免扫描表中很多已知不包含匹配元组的部分。
一个BRIN索引将存储的特定数据以及该索引将能 满足的特定查询,都依赖于为该索引的每一列所选择的操作符类。具有一种 线性排序顺序的数据类型的操作符类可以存储在每个块范围内的最小和最大 值,例如几何类型可能会存储在块范围内的所有对象的外包盒。
块范围的尺寸在索引创建时由pages_per_range
存储参数决定。
索引项的数量将等于该关系的尺寸(以页面计)除以为
pages_per_range
选择的值。因此,该值越小,索引会变得越大
(因为需要存储更多索引项),但是与此同时存储的摘要数据可以更加精确并
且在索引扫描期间可以跳过更多数据块。
在创建时,所有已有的堆页面将被扫描并且会为每一个范围创建一个摘要
索引元组,对于末尾的可能不完整的范围也是这样做。随着新页面被数据填
充,已经被创建摘要的页面范围的摘要信息会被来自新元组的数据所更新。
当一个被创建的新页面没有落在最后一个被摘要的范围内时,该范围不会自
动获得一个摘要元组,那些元组将保持未被摘要的状态,直到后面调用一次
摘要操作来创建初始的摘要。可以使用brin_summarize_range(regclass, bigint)
或brin_summarize_new_values(regclass)
函数手动调用这种处理,而当VACUUM
处理表时或者插入发生时由autovacuum执行的自动摘要过程都会自动调用这种处理(最后这一个触发器默认是被禁用的,可以用autosummarize
参数启用。相对地,可以用brin_desummarize_range(regclass, bigint)
函数解除一个范围的摘要,在现有值发生变化导致索引元组不再是一个很好的表达式,这样做是很有用的。
当自动摘要被启用时,每次一个页面范围会被装进一个请求中发送给autovacuum,以便autovacuum为那个范围执行定向的摘要,这个请求会在运行在同一个数据库的下一个工作者的末尾被满足。如果请求队列满了,该请求不会被记录,并且在服务器日志中会有一条消息:
LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was not recorded
如果这种情况发生,在该表的下一次常规vacuum时将会正常对这个范围做摘要。