Индексы BRIN

Введение

BRIN расшифровывается как Block Range Index (индекс диапазона блоков). BRIN предназначен для обработки очень больших таблиц, в которых определенные столбцы имеют некую естественную корреляцию с их физическим расположением в таблице. Диапазон блоков — это группа страниц, которые физически соседствуют в таблице; для каждого диапазона блоков в индексе сохраняется некоторая сводная информация. Например, таблица, хранящая заказы на поставку, может иметь столбец даты добавления каждого заказа, и в большинстве случаев записи для более ранних заказов в таблице будут размещены выше; в таблице со столбцом почтового индекса могут храниться все коды городов, сгруппированные естественным образом.

Индексы BRIN удовлетворяют запросы посредством обычного сканирования по битовой карте, возвращая все кортежи всех страниц в каждом диапазоне, если сводная информация, сохраненная в индексе, согласуется с условиями запроса. Исполнитель запроса отвечает за перепроверку этих кортежей и сброс тех, что не соответствуют условиям запроса — другими словами, эти индексы крайне неточные. Но поскольку индекс BRIN очень мал, сканирование индекса добавляет мало накладных расходов по сравнению с последовательным сканированием, при этом помогая избежать сканирования больших областей таблицы, которые определенно не содержат подходящих кортежей.

Конкретные данные, которые будет хранить индекс BRIN, а также конкретные запросы, которые этот индекс сможет удовлетворить, зависят от класса операторов, выбранного для каждого столбца индекса. Например, типы данных с линейным порядком сортировки могут иметь классы операторов, которые хранят минимальное и максимальное значение в каждом диапазоне блоков; геометрические типы могут хранить ограничивающую рамку для всех объектов в диапазоне блоков.

Размер диапазона блоков определяется во время создания индекса параметром хранения pages_per_range. Количество записей индекса будет равно размеру отношения в страницах, деленному на выбранное значение pages_per_range. Чем меньше число, тем больше размер индекса (из-за необходимости хранить больше записей), но в то же время может повыситься точность сохраняемой сводной информации, а во время сканирования можно будет пропустить больше блоков данных.

Обслуживание индекса

Во время создания индекса сканируются все существующие страницы кучи, и для каждого диапазона, включая возможно неполный диапазон в конце, создается сводный кортеж индекса. По мере того, как данными наполняются новые страницы, в диапазонах страниц, для которых уже есть сводная информация, эта информация обновляется данными из новых кортежей. Когда создается новая страница, не попадающая в последний диапазон, для которого есть сводка, новый диапазон не получает автоматически кортеж со сводкой; эти кортежи остаются неучтенными, пока позже не запустится расчет сводных данных, создавая начальные сводки. Этот процесс можно запустить вручную с помощью функции brin_summarize_range(regclass, bigint) или brin_summarize_new_values(regclass) либо автоматически, когда таблицу будет обрабатывать VACUUM, или посредством автоматического создания сводки, выполняемого при автоочистке, по мере добавления записей. (Последний триггер по умолчанию выключен и может быть включен параметром autosummarize.) И наоборот, можно удалить сводку для диапазона при помощи функции brin_desummarize_range (regclass, bigint), что полезно, когда кортеж индекса перестает быть хорошим представлением данных, так как они изменились.

Когда включен режим автопересчета сводки, при каждом заполнении диапазона страниц механизма автоочистки посылается запрос на выполнение целевого пересчета для этого диапазона, который будет произведен в конце следующего прохода рабочего процесса в той же базе данных. Если очередь запросов переполнена, запрос в нее не записывается, а в журнал сервера передается следующее сообщение:

LOG:  request for BRIN range summarization for index "brin_wi_idx" page 128 was not recorded
(ЗАПИСЬ: запрос на сводку диапазона BRIN для страницы 128 индекса "brin_wi_idx" не был записан)

Когда это происходит, сводка для такого диапазона рассчитывается обычным образом при выполнении следующей регулярной очистки таблицы.

Встроенные классы операторов

Основной дистрибутив QHB включает классы операторов BRIN, показанные в Таблице 1.

Классы операторов minmax хранят минимальное и максимальное значения, встречающиеся в индексированном столбце в пределах определенного диапазона. Классы операторов inclusion хранят значение, в котором содержатся значения индексированного столбца в пределах определенного диапазона. Классы операторов bloom строят фильтр Блума для всех значений в определенном диапазоне. Классы операторов minmax-multi хранят несколько минимальных и максимальных значений, представляющих значения, встречающиеся в индексированном столбце в пределах определенного диапазона.

Таблица 1. Встроенные классы операторов BRIN

Имя
Индексируемые операторы
bit_minmax_ops = (bit,bit)
< (bit,bit)
<= (bit,bit)
> (bit,bit)
>= (bit,bit)
box_inclusion_ops @> (box,point)
<< (box,box)
&< (box,box)
&> (box,box)
>> (box,box)
<@ (box,box)
@> (box,box)
~= (box,box)
~= (box,box)
<<| (box,box)
&<| (box,box)
|&> (box,box)
|>> (box,box)
bpchar_bloom_ops = (character,character)
bpchar_minmax_ops = (character,character)
< (character,character)
<= (character,character)
> (character,character)
>= (character,character)
bytea_bloom_ops = (bytea,bytea)
bytea_minmax_ops = (bytea,bytea)
< (bytea,bytea)
<= (bytea,bytea)
> (bytea,bytea)
>= (bytea,bytea)
char_bloom_ops = ("char","char")
char_minmax_ops = ("char","char")
< ("char","char")
<= ("char","char")
> ("char","char")
>= ("char","char")
date_bloom_ops = (date,date)
date_minmax_ops = (date,date)
< (date,date)
<= (date,date)
> (date,date)
>= (date,date)
date_minmax_multi_ops = (date,date)
< (date,date)
<= (date,date)
> (date,date)
>= (date,date)
float4_bloom_ops = (float4,float4)
float4_minmax_ops = (float4,float4)
< (float4,float4)
<= (float4,float4)
> (float4,float4)
>= (float4,float4)
float4_minmax_multi_ops = (float4,float4)
< (float4,float4)
<= (float4,float4)
> (float4,float4)
>= (float4,float4)
float8_bloom_ops = (float8,float8)
float8_minmax_ops = (float8,float8)
< (float8,float8)
<= (float8,float8)
> (float8,float8)
>= (float8,float8)
float8_minmax_multi_ops = (float8,float8)
< (float8,float8)
<= (float8,float8)
> (float8,float8)
>= (float8,float8)
inet_inclusion_ops << (inet,inet)
<<= (inet,inet)
>> (inet,inet)
>>= (inet,inet)
= (inet,inet)
&& (inet,inet)
inet_bloom_ops = (inet,inet)
inet_minmax_ops = (inet,inet)
< (inet,inet)
<= (inet,inet)
> (inet,inet)
>= (inet,inet)
inet_minmax_multi_ops = (inet,inet)
< (inet,inet)
<= (inet,inet)
> (inet,inet)
>= (inet,inet)
int2_bloom_ops = (int2,int2)
int2_minmax_ops = (int2,int2)
< (int2,int2)
<= (int2,int2)
> (int2,int2)
>= (int2,int2)
int2_minmax_multi_ops = (int2,int2)
< (int2,int2)
<= (int2,int2)
> (int2,int2)
>= (int2,int2)
int4_bloom_ops = (int4,int4)
int4_minmax_ops = (int4,int4)
< (int4,int4)
<= (int4,int4)
> (int4,int4)
>= (int4,int4)
int4_minmax_multi_ops = (int4,int4)
< (int4,int4)
<= (int4,int4)
> (int4,int4)
>= (int4,int4)
int8_bloom_ops = (bigint,bigint)
int8_minmax_ops = (bigint,bigint)
< (bigint,bigint)
<= (bigint,bigint)
> (bigint,bigint)
>= (bigint,bigint)
int8_minmax_multi_ops = (bigint,bigint)
< (bigint,bigint)
<= (bigint,bigint)
> (bigint,bigint)
>= (bigint,bigint)
interval_bloom_ops = (interval,interval)
interval_minmax_ops = (interval,interval)
< (interval,interval)
<= (interval,interval)
> (interval,interval)
>= (interval,interval)
interval_minmax_multi_ops = (interval,interval)
< (interval,interval)
<= (interval,interval)
> (interval,interval)
>= (interval,interval)
macaddr_bloom_ops = (macaddr,macaddr)
macaddr_minmax_ops = (macaddr,macaddr)
< (macaddr,macaddr)
<= (macaddr,macaddr)
> (macaddr,macaddr)
>= (macaddr,macaddr)
macaddr_minmax_multi_ops = (macaddr,macaddr)
< (macaddr,macaddr)
<= (macaddr,macaddr)
> (macaddr,macaddr)
>= (macaddr,macaddr)
macaddr8_bloom_ops = (macaddr8,macaddr8)
macaddr8_minmax_ops = (macaddr8,macaddr8)
< (macaddr8,macaddr8)
<= (macaddr8,macaddr8)
> (macaddr8,macaddr8)
>= (macaddr8,macaddr8)
macaddr8_minmax_multi_ops = (macaddr8,macaddr8)
< (macaddr8,macaddr8)
<= (macaddr8,macaddr8)
> (macaddr8,macaddr8)
>= (macaddr8,macaddr8)
name_bloom_ops = (name,name)
name_minmax_ops = (name,name)
< (name,name)
<= (name,name)
> (name,name)
>= (name,name)
numeric_bloom_ops = (numeric,numeric)
numeric_minmax_ops = (numeric,numeric)
< (numeric,numeric)
<= (numeric,numeric)
> (numeric,numeric)
>= (numeric,numeric)
numeric_minmax_multi_ops = (numeric,numeric)
< (numeric,numeric)
<= (numeric,numeric)
> (numeric,numeric)
>= (numeric,numeric)
oid_bloom_ops = (oid,oid)
oid_minmax_ops = (oid,oid)
< (oid,oid)
<= (oid,oid)
> (oid,oid)
>= (oid,oid)
oid_minmax_multi_ops = (oid,oid)
< (oid,oid)
<= (oid,oid)
> (oid,oid)
>= (oid,oid)
pg_lsn_bloom_ops = (pg_lsn,pg_lsn)
pg_lsn_minmax_ops = (pg_lsn,pg_lsn)
< (pg_lsn,pg_lsn)
<= (pg_lsn,pg_lsn)
> (pg_lsn,pg_lsn)
>= (pg_lsn,pg_lsn)
pg_lsn_minmax_multi_ops = (pg_lsn,pg_lsn)
< (pg_lsn,pg_lsn)
<= (pg_lsn,pg_lsn)
> (pg_lsn,pg_lsn)
>= (pg_lsn,pg_lsn)
range_inclusion_ops = (anyrange,anyrange)
< (anyrange,anyrange)
<= (anyrange,anyrange)
> (anyrange,anyrange)
>= (anyrange,anyrange)
&& (anyrange,anyrange)
@> (anyrange,anyelement)
@> (anyrange,anyrange)
<@ (anyrange,anyrange)
<< (anyrange,anyrange)
>> (anyrange,anyrange)
&< (anyrange,anyrange)
&> (anyrange,anyrange)
-|- (anyrange,anyrange)
text_bloom_ops = (text,text)
text_minmax_ops = (text,text)
< (text,text)
<= (text,text)
> (text,text)
>= (text,text)
tid_bloom_ops = (tid,tid)
tid_minmax_ops = (tid,tid)
< (tid,tid)
<= (tid,tid)
> (tid,tid)
>= (tid,tid)
tid_minmax_multi_ops = (tid,tid)
< (tid,tid)
<= (tid,tid)
> (tid,tid)
>= (tid,tid)
timestamp_bloom_ops = (timestamp,timestamp)
timestamp_minmax_ops = (timestamp,timestamp)
< (timestamp,timestamp)
<= (timestamp,timestamp)
> (timestamp,timestamp)
>= (timestamp,timestamp)
timestamp_minmax_multi_ops = (timestamp,timestamp)
< (timestamp,timestamp)
<= (timestamp,timestamp)
> (timestamp,timestamp)
>= (timestamp,timestamp)
timestamptz_bloom_ops = (timestamptz,timestamptz)
timestamptz_minmax_ops = (timestamptz,timestamptz)
< (timestamptz,timestamptz)
<= (timestamptz,timestamptz)
> (timestamptz,timestamptz)
>= (timestamptz,timestamptz)
timestamptz_minmax_multi_ops = (timestamptz,timestamptz)
< (timestamptz,timestamptz)
<= (timestamptz,timestamptz)
> (timestamptz,timestamptz)
>= (timestamptz,timestamptz)
time_bloom_ops = (time,time)
time_minmax_ops = (time,time)
< (time,time)
<= (time,time)
> (time,time)
>= (time,time)
time_minmax_multi_ops = (time,time)
< (time,time)
<= (time,time)
> (time,time)
>= (time,time)
timetz_bloom_ops = (timetz,timetz)
timetz_minmax_ops = (timetz,timetz)
< (timetz,timetz)
<= (timetz,timetz)
> (timetz,timetz)
>= (timetz,timetz)
timetz_minmax_multi_ops = (timetz,timetz)
< (timetz,timetz)
<= (timetz,timetz)
> (timetz,timetz)
>= (timetz,timetz)
uuid_bloom_ops = (uuid,uuid)
uuid_minmax_ops = (uuid,uuid)
< (uuid,uuid)
<= (uuid,uuid)
> (uuid,uuid)
>= (uuid,uuid)
uuid_minmax_multi_ops = (uuid,uuid)
< (uuid,uuid)
<= (uuid,uuid)
> (uuid,uuid)
>= (uuid,uuid)
varbit_minmax_ops = (varbit,varbit)
< (varbit,varbit)
<= (varbit,varbit)
> (varbit,varbit)
>= (varbit,varbit)

Параметры класса операторов

Для некоторых встроенных классов операторов разрешено задавать параметры, влияющие на их поведение. У каждого класса операторов имеется собственный набор допустимых операторов. Указывать параметры можно только для классов операторов bloom и minmax-multi.

Классы операторов bloom принимают следующие параметры:

n_distinct_per_range
Определяет предположительное количество уникальных значений, отличных от NULL, в диапазоне блоков, используемых индексами BRIN типа bloom для установки размера фильтра Блума. Его поведение аналогично таковому у параметра n_distinct для ALTER TABLE. Когда задается положительное значение, считается, что каждый диапазон блоков содержит именно это количество уникальных значений, отличных от NULL. Когда задается отрицательное значение, которое должно быть больше либо равно -1, считается, что количество уникальных значений, отличных от NULL, линейно возрастает в зависимости от максимально возможного количества кортежей в диапазоне блоков (примерно 290 строк на блок). По умолчанию установлено значение -0.1, а минимальное количество уникальных значений, отличных от NULL, которое можно задать, равно 16.

false_positive_rate
Определяет целевую долю ложноположительных срабатываний, используемых индексами BRIN типа bloom для установки размера фильтра Блума. Значение должно находиться в пределах от 0.0001 до 0.25. Значение по умолчанию равно 0.01, т. е. доля ложноположительных срабатываний составляет 1%.

Классы операторов minmax-multi принимают следующие параметры:

values_per_range
Определяет максимальное количество значений, хранимых индексами BRIN типа minmax для создания сводки по диапазону блоков. Каждое значение может представлять либо точку, либо границу интервала. Значения должны находиться в пределах от 8 до 256, а значение по умолчанию равно 32.

Расширяемость

Интерфейс BRIN имеет высокий уровень абстракции, требующий от разработчика метода доступа описать только семантику обрабатываемого типа данных. Сам уровень BRIN обеспечивает параллельный доступ, протоколирование в журнал и поиск в структуре индекса.

Все, что требуется, чтобы получить работающий метод доступа BRIN, — это реализовать несколько пользовательских методов, которые определят поведение сводных значений, хранящихся в индексе, и их взаимодействие с ключами сканирования. Иными словами, BRIN сочетает расширяемость с универсальностью, повторным использованием кода и простым интерфейсом.

Существует четыре метода, которые должен предоставить класс операторов для BRIN:

opcInfo

BrinOpcInfo *opcInfo(Oid type_oid)

Возвращает внутреннюю информацию о сводных данных индексированных столбцов. Возвращаемое значение должно указывать на BrinOpcInfo, выделенную с помощью palloc, имеющую следующее определение:

typedef struct BrinOpcInfo
{
    /* Число столбцов, хранящихся в столбце индекса этого класса операторов */
    uint16      oi_nstored;

    /* Непрозрачный указатель для внутреннего использования классом операторов */
    void       *oi_opaque;

    /* Записи кэша типов для сохраненных столбцов */
    TypeCacheEntry *oi_typcache[FLEXIBLE_ARRAY_MEMBER];
} BrinOpcInfo;

Brinpcinfo.oi_opaque могут использовать процедуры класса операторов для передачи информации между вспомогательными функциями при сканировании индекса.

consistent

bool consistent(BrinDesc *bdesc, BrinValues *column, ScanKey *keys, int nkeys)

Показывает, все ли записи ScanKey соответствуют заданным индексированным значениям некоторого диапазона. Номер целевого атрибута передается как часть ключа сканирования. Для одного атрибута может передаваться несколько ключей сканирования; количество записей определяется параметром nkeys.

bool consistent(BrinDesc *bdesc, BrinValues *column, ScanKey key)

Показывает, соответствует ли эта запись ScanKey заданным индексированным значениям некоторого диапазона. Номер целевого атрибута передается как часть ключа сканирования. Это более старый обратно совместимый вариант функции consistent.

addValue

bool addValue(BrinDesc *bdesc, BrinValues *column, Datum newval, bool isnull)

Для заданного кортежа индекса и индексируемого значения изменяет указанный атрибут кортежа, чтобы тот дополнительно представлял новое значение. Если кортеж каким-либо образом менялся, возвращается true.

unionTuples

bool unionTuples(BrinDesc *bdesc, BrinValues *a, BrinValues *b)

Консолидирует два кортежа индекса. Для двух заданных кортежей индекса изменяет указанный атрибут первого из них, чтобы тот представлял оба кортежа. Второй кортеж не изменяется. .

Дополнительно класс операторов для BRIN может задать следующий метод:

options

void options(local_relopts *relopts)

Определяет набор видимых пользователю параметров, управляющих поведением класса операторов.

Функции options передается указатель на структуру local_relopts, которую нужно заполнить набором параметров, специфичных для класса операторов. К этим параметрам можно обращаться из других вспомогательных функций с помощью макросов PG_HAS_OPCLASS_OPTIONS() и PG_GET_OPCLASS_OPTIONS().

Поскольку в BRIN извлечение ключа из индексируемых значений и представление этого ключа допускают гибкость, они могут зависеть от параметров, заданных пользователем. .

Основной дистрибутив включает поддержку четырех типов классов операторов: minmax, minmax-multi, inclusion и bloom. Использующие их определения классов операторов поставляются для резидентных типов данных по мере необходимости. Для других типов данных пользователь может определить дополнительные классы операторов с помощью равнозначных определений без необходимости писать какой-либо исходный код; достаточно объявить подходящие записи в каталоге. Обратите внимание, что предположения о семантике стратегий операторов зашиты в исходном коде вспомогательных функций.

Также возможно создать классы операторов, воплощающие совершенно иную семантику, предоставив реализации четырех основных вспомогательных функций, описанных выше. Обратите внимание, что обратная совместимость между разными основными версиями не гарантируется: например, в следующих выпусках могут потребоваться дополнительные вспомогательные функции.

Для написания класса операторов для типа данных, реализующего полностью упорядоченное множество, можно воспользоваться вспомогательными функциями minmax наряду с соответствующими операторами, как показано в Таблице 2. Все члены класса операторов (функции и операторы) являются обязательными.

Таблица 2. Номера стратегий и вспомогательных функций для классов операторов minmax

Член класса операторовОбъект
Вспомогательная функция 1внутренняя функция brin_minmax_opcinfo()
Вспомогательная функция 2внутренняя функция brin_minmax_add_value()
Вспомогательная функция 3внутренняя функция brin_minmax_consistent()
Вспомогательная функция 4внутренняя функция brin_minmax_union()
Стратегия оператора 1оператор меньше
Стратегия оператора 2оператор меньше-или-равно
Стратегия оператора 3оператор равно
Стратегия оператора 4оператор больше-или-равно
Стратегия оператора 5оператор больше

Для написания класса операторов для сложного типа данных, значения которого включены в другой тип, можно воспользоваться вспомогательными функциями inclusion наряду с соответствующими операторами, как показано в Таблице 3. Для этого требуется всего одна дополнительная функция, которую можно написать на любом языке. Для дополнительной функциональности можно определить больше функций. Все операторы являются необязательными. Некоторым из них требуется наличие других операторов, что показано в таблице в виде зависимостей.

Таблица 3. Номера стратегий и вспомогательных функций для классов операторов inclusion

Член класса операторовОбъектЗависимость
Вспомогательная функция 1внутренняя функция brin_inclusion_opcinfo() 
Вспомогательная функция 2внутренняя функция brin_inclusion_add_value() 
Вспомогательная функция 3внутренняя функция brin_inclusion_consistent() 
Вспомогательная функция 4внутренняя функция brin_inclusion_union() 
Вспомогательная функция 11функция для слияния двух элементов 
Вспомогательная функция 12необязательная функция для проверки возможности слияния двух элементов 
Вспомогательная функция 13необязательная функция для проверки, содержится ли один элемент в другом 
Вспомогательная функция 14необязательная функция для проверки, является ли элемент пустым 
Стратегия оператора 1оператор левееСтратегия оператора 4
Стратегия оператора 2оператор не-простирается-правееСтратегия оператора 5
Стратегия оператора 3оператор перекрывается 
Стратегия оператора 4оператор не-простирается-левееСтратегия оператора 1
Стратегия оператора 5оператор правееСтратегия оператора 2
Стратегия оператора 6, 18оператор то-же-или-равноСтратегия оператора 7
Стратегия оператора 7, 13, 16, 24, 25оператор содержит-или-равно
Стратегия оператора 8, 14, 26, 27оператор содержится-в-или-равноСтратегия оператора 3
Стратегия оператора 9оператор не-простирается-вышеСтратегия оператора 11
Стратегия оператора 10оператор нижеСтратегия оператора 12
Стратегия оператора 11оператор вышеСтратегия оператора 9
Стратегия оператора 12оператор не-простирается-нижеСтратегия оператора 10
Стратегия оператора 20оператор меньшеСтратегия оператора 5
Стратегия оператора 21оператор меньше-или-равноСтратегия оператора 5
Стратегия оператора 22оператор большеСтратегия оператора 1
Стратегия оператора 23оператор больше-или-равноСтратегия оператора 1

Номера вспомогательных функций от 1 до 10 зарезервированы для внутренних функций BRIN, поэтому функции уровня SQL начинаются с номера 11. Вспомогательная функция номер 11 является основной функцией, требуемой для постройки индекса. Она должна принимать два аргумента с тем же типом данных, что и у класса операторов, и возвращать их объединение. Класс операторов inclusion может сохранять объединенные значения в различных типах данных, если это определено в параметре STORAGE. Значение, возвращаемое функцией объединения, должно соответствовать типу данных STORAGE.

Вспомогательные функции номер 12 и номер 14 предоставляются для поддержки нерегулярностей встроенных типов данных. Функция номер 12 используется для поддержки сетевых адресов из различных семейств, которые нельзя объединять. Функция номер 14 используется для поддержки пустых диапазонов. Функция номер 13 является необязательной, но рекомендуемой; она позволяет проверить новое значение, прежде чем оно будет передано функции объединения. Поскольку инфраструктура BRIN может упростить некоторые операции, когда объединение не меняется, использование этой функции может повысить производительность индекса.

Для написания класса операторов для типа данных, реализующего только оператор равенства и поддерживающего хэширование, можно использовать вспомогательные процедуры bloom наряду с соответствующими операторами, как показано в Таблице 4. Все члены класса операторов (процедуры и операторы) являются обязательными.

Таблица 4. Номера стратегий и вспомогательных процедур для классов операторов bloom

Член класса операторовОбъект
Вспомогательная процедура 1внутренняя функция brin_bloom_opcinfo()
Вспомогательная процедура 2внутренняя функция brin_bloom_add_value()
Вспомогательная процедура 3внутренняя функция brin_bloom_consistent()
Вспомогательная процедура 4внутренняя функция brin_bloom_union()
Вспомогательная процедура 11функция для вычисления хэша элемента
Стратегия оператора 1оператор равно

Номера вспомогательных процедур 1-10 зарезервированы для внутренних функций BRIN, поэтому функции уровня SQL начинаются с номера 11. Вспомогательная функция номер 11 является основной функцией, требуемой для построения индекса. Она должна принимать один аргумент с тем же типом данных, что и у класса операторов, и возвращать хэш этого значения.

Класс операторов minmax-multi также предназначен для типов данных, реализующих полностью упорядоченное множество, и может рассматриваться просто как расширение класса операторов minmax. В то время как класс операторов minmax рассчитывает сводку по значениям из каждого диапазона блоков как один непрерывный интервал, minmax-multi позволяет рассчитать сводку в виде нескольких меньших интервалов для более эффективной обработки выпадающих значений. Можно использовать вспомогательные процедуры minmax-multi наряду с соответствующими операторами, как показано в Таблице 5. Все члены класса операторов (процедуры и операторы) являются обязательными.

Таблица 5. Номера стратегий и вспомогательных процедур для классов операторов minmax-multi

Член класса операторовОбъект
Вспомогательная процедура 1внутренняя функция brin_minmax_multi_opcinfo()
Вспомогательная процедура 2внутренняя функция brin_minmax_multi_add_value()
Вспомогательная процедура 3внутренняя функция brin_minmax_multi_consistent()
Вспомогательная процедура 4внутренняя функция brin_minmax_multi_union()
Вспомогательная процедура 11функция для вычисления расстояния между двумя значениями (длины диапазона)
Стратегия оператора 1оператор меньше
Стратегия оператора 2оператор меньше-или-равно
Стратегия оператора 3оператор равно
Стратегия оператора 4оператор больше-или-равно
Стратегия оператора 5оператор больше

Классы операторов minmax и inclusion поддерживают операторы с разными типами данных, хотя с ними зависимости становятся более сложными. Классу операторов minmax требуется, чтобы для двух аргументов одного типа определялся полный набор операторов. Это позволяет поддерживать дополнительные типы данных, определяя дополнительные наборы операторов. Стратегии класса операторов inclusion зависят от других стратегий, как показано в Таблице 3, или от своих собственных стратегий оператора. Для них требуется, чтобы оператор зависимости был определен с типом данных STORAGE в качестве левого аргумента и другим поддерживаемым типом в качестве правого аргумента поддерживаемого оператора. См. определение float4_minmax_ops в качестве примера minmax и box_inclusion_ops в качестве примера inclusion.