Введение
BRIN расшифровывается как Block Range Index (индекс диапазона блоков). BRIN предназначен для работы с очень большими таблицами, в которых определенные столбцы имеют естественную корреляцию с их физическим расположением в таблице.
BRIN работает в терминах диапазонов блоков (или «диапазонов страниц»). Диапазон блоков - это группа страниц, которые физически соседствуют в таблице; для каждого диапазона блоков индекс хранит некоторую сводную информацию. Например, таблица, хранящая заказы на продажу в магазине, может иметь столбец даты, когда был сделан каждый заказ, и в большинстве случаев записи о более ранних заказах также будут появляться раньше в таблице; таблица, хранящая столбец ZIP-кодов, может иметь все коды для города, сгруппированные вместе естественным образом.
Индексы BRIN могут удовлетворять запросы с помощью обычного сканирования растрового индекса и возвращать все кортежи на всех страницах в каждом диапазоне, если суммарная информация, хранящаяся в индексе, соответствует условиям запроса. Исполнитель запроса отвечает за перепроверку этих кортежей и отбрасывает те, которые не соответствуют условиям запроса - другими словами, эти индексы работают с потерями. Поскольку BRIN-индекс очень мал, сканирование индекса не требует больших затрат по сравнению с последовательным сканированием, но позволяет избежать сканирования больших частей таблицы, которые, как известно, не содержат соответствующих кортежей.
Конкретные данные, которые будет хранить индекс BRIN, а также конкретные запросы, которые индекс сможет удовлетворить, зависят от класса оператора, выбранного для каждого столбца индекса. Например, типы данных с линейным порядком сортировки могут иметь классы операторов, которые хранят минимальное и максимальное значение в каждом диапазоне блоков; геометрические типы могут хранить граничные рамки для всех объектов в диапазоне блоков.
Размер диапазона блоков определяется во время создания индекса параметром хранения pages_per_range
. Количество записей индекса будет равно размеру отношения в страницах, деленному на выбранное значение pages_per_range
. Таким образом, чем меньше это число, тем больше становится индекс (из-за необходимости хранить больше записей индекса), но в то же время хранимые сводные данные могут быть более точными, и при сканировании индекса можно пропустить больше блоков данных.
Обслуживание индекса
В момент создания все существующие страницы кучи сканируются, и для каждого диапазона, включая, возможно, неполный диапазон в конце, создается кортеж сводного индекса. По мере заполнения новых страниц данными диапазоны страниц, которые уже просуммированы, будут обновлять сводную информацию с помощью данных из новых кортежей. Когда создается новая страница, не входящая в последний просуммированный диапазон, диапазон, к которому принадлежит новая страница, не получает автоматически кортеж сводки; эти кортежи остаются не просуммированными до тех пор, пока позже не будет вызван прогон суммирования, создающий первоначальную сводку для этого диапазона.
Существует несколько способов инициировать первоначальное суммирование диапазона страниц. Если таблица пылесосится вручную или с помощью autovacuum, все существующие не суммированные диапазоны страниц суммируются. Кроме того, если параметр autosummarize индекса включен, а по умолчанию он не включен, то при каждом запуске autovacuum в этой базе данных суммирование будет происходить для всех заполненных не суммированных диапазонов страниц, независимо от того, обрабатывается ли сама таблица autovacuum; см. ниже.
Наконец, можно использовать следующие функции:
brin_summarize_new_values(regclass)
– суммирует все не суммированные диапазоны;brin_summarize_range(regclass, bigint)
– суммирует только диапазон, содержащий заданную страницу, если она не суммирована.
Если включена функция автосуммирования, в autovacuum
отправляется запрос на выполнение целевого суммирования для диапазона блоков при обнаружении вставки для первого элемента первой страницы следующего диапазона блоков, который должен быть выполнен в следующий раз, когда рабочий autovacuum завершит работу в той же базе данных. Если очередь запросов переполнена, запрос не записывается, а сообщение отправляется в журнал сервера:
LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was not recorded
Если это произойдет, диапазон останется не суммированным до следующего регулярного прогона таблицы или вызова одной из функций, упомянутых выше.
И наоборот, диапазон может быть десуммирован с помощью функции brin_desummarize_range(regclass, bigint)
, которая полезна, когда кортеж индексов уже не является очень хорошим представлением, поскольку существующие значения изменились.