Перейти к основному содержимому

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

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

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

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

BrinOpcInfo *opcInfo(Oid type_oid)

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

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 наряду с соответствующими операторами, как показано в таблице «Номера стратегий и опорных функций для классов операторов minmax». Все члены операторного класса (функции и операторы) являются обязательными.

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

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

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

Номера стратегий и опорных функций для классов операторов 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, 16, 24, 25Оператор содержит-или-равно
Стратегия оператора 8, 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 - это основная функция, необходимая для построения индекса. Она должна принимать два аргумента с тем же типом данных, что и класс оператора, и возвращать их объединение. Класс оператора включения может хранить значения объединения с разными типами данных, если он определен с помощью параметра STORAGE. Возвращаемое значение функции объединения должно соответствовать типу данных STORAGE.

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

Чтобы написать класс оператора для типа данных, реализующего только оператор равенства и поддерживающего хеширование, можно использовать процедуры поддержки bloom наряду с соответствующими операторами, как показано в таблице «Номера стратегий и опорных процедур для классов операторов bloom». Все члены класса оператора (процедуры и операторы) являются обязательными.

Номера стратегий и опорных процедур для классов операторов 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 можно использовать наряду с соответствующими операторами, как показано в таблице «Номера стратегий и опорных процедур для классов операторов minmax-multi». Все члены класса операторов (процедуры и операторы) являются обязательными.

Номера стратегий и опорных процедур для классов операторов 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», или от той же самой операторной стратегии как таковой. Они требуют, чтобы оператор зависимости был определен с типом данных STORAGE в качестве аргумента левой стороны, а другой поддерживаемый тип данных - в качестве аргумента правой стороны поддерживаемого оператора. См. float4_minmax_ops в качестве примера minmax и box_inclusion_ops в качестве примера inclusion.