64.5. Индексы BRIN#

64.5. Индексы BRIN

64.5. Индексы BRIN #

64.5.1. Введение #

BRIN расшифровывается как Block Range Index. BRIN предназначен для работы с очень большими таблицами, в которых определенные столбцы имеют естественную корреляцию с их физическим расположением внутри таблицы.

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

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

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

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

64.5.1.1. Обслуживание индексов #

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

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

Наконец, можно использовать следующие функции (пока эти функции выполняются, search_path временно изменяется на pg_catalog, pg_temp):

brin_summarize_new_values(regclass) которая суммирует все несуммированные диапазоны;
brin_summarize_range(regclass, bigint) которая суммирует только диапазон, содержащий данную страницу, если он не был ранее суммирован.

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

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

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

Обратно, диапазон может быть развернут с использованием функции brin_desummarize_range(regclass, bigint), которая полезна, когда кортеж индекса больше не является очень хорошим представлением, потому что существующие значения изменились. См. Раздел 9.28.8 для получения подробной информации.

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

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

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

Таблица 64.4. Встроенные классы операторов 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)

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

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

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

n_distinct_per_range

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

false_positive_rate

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

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

values_per_range

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

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

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

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

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

BrinOpcInfo *opcInfo(Oid type_oid)

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

typedef struct BrinOpcInfo
{
    /* Number of columns stored in an index column of this opclass */
    uint16      oi_nstored;

    /* Opaque pointer for the opclass' private use */
    void       *oi_opaque;

    /* Type cache entries of the stored columns */
    TypeCacheEntry *oi_typcache[FLEXIBLE_ARRAY_MEMBER];
} BrinOpcInfo;

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

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

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

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

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

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

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

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

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

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

void options(local_relopts *relopts)

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

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

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

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

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

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

Таблица 64.5. Функции и номера опорных функций для классов операторов Minmax

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

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

Таблица 64.6. Функции и номера опорных функций для классов операторов включения

Оператор класса членОбъектЗависимость
Опорная функция 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оператор same-as-or-equal-toСтратегия оператора 7
Стратегия оператора 7, 16, 24, 25оператор содержит-или-равно 
Стратегия оператора 8, 26, 27оператор is-contained-by-or-equal-toСтратегия оператора 3
Стратегия оператора 9оператор не расширяется вышеСтратегия оператора 11
Стратегия оператора 10оператор is-belowСтратегия оператора 12
Стратегия оператора 11оператор is-aboveСтратегия оператора 9
Стратегия оператора 12оператор does-not-extend-belowСтратегия оператора 10
Стратегия оператора 20оператор меньше-чемСтратегия оператора 5
Стратегия оператора 21оператор меньше или равноСтратегия оператора 5
Стратегия оператора 22оператор больше-чемСтратегия оператора 1
Стратегия оператора 23оператор больше или равноСтратегия оператора 1

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

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

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

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

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

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

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

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

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

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