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

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

69.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 вместе с соответствующими операторами, как показано в Таблица 69.2. Все члены класса операторов (функции и операторы) являются обязательными.

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

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

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

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

Оператор класса членОбъектЗависимость
Опорная функция 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 вместе с соответствующими операторами, как показано в разделе Таблица 69.4. Все элементы класса операторов (процедуры и операторы) являются обязательными.

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

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