В этом разделе описано, как эффективно использовать векторизованный движок выполнения.
Прежде всего, для различных сценариев улучшение производительности векторизованного движка выполнения по сравнению с традиционными строковыми движками различается. Вы можете получить базовое представление об этом через раздел обзора.
Например, операторы, которые могут работать в полном последовательном порядке — такие как вычисления общих выражений, операторы фильтрации и агрегации — могут максимально повысить производительность. Для операторов со случайным доступом, таких как операторы сортировки и хеширования, потенциал для улучшения производительности ограничен.
Рекомендуется использовать примитивные типы (например, int32, int64 и т.д.) для повышения производительности и эффективности векторизации.
Часто поля перечислений используются для операций фильтрации, например, поля страны или китайских провинций. Их можно представлять строками, такими как "Китай", "США", "Пекин", "Синьцзян" и т.д., но если предварительно обработать данные и заменить их на smallint, это значительно ускорит операции фильтрации.
Если поле возраста может быть полностью представлено типом smallint, нет необходимости использовать int32 или даже int64.
Для традиционных движков выполнения, независимо от числового типа, кортеж в финальном результате часто представляется как Datum, занимающий 64 бита. Datum может хранить любое значение любого SQL-типа, но сам по себе не содержит информации о типе данных. Поэтому использование разных типов не влияет на скорость обработки.
Однако для векторизованных движков данные располагаются непрерывно и плотно. Чем короче тип значения, тем лучше оно соответствует кэшу CPU, и тем больше данных может поместиться в SIMD-регистры. Таким образом, фильтрация или агрегация определённого столбца с использованием int64 будет в четыре раза медленнее, чем с int16.
Примечание!
Из-за ограничений по времени и ресурсам мы не реализовали все типы данных, выражения и запросы, поддерживаемые стандартами баз данных. Однако для обеспечения работоспособности при обнаружении неподдерживаемых ситуаций система частично или полностью переключается на традиционный движок выполнения, что проявляется в незначительном или отсутствующем улучшении производительности.
Вы можете вручную отключить параметр matrix.enable_mxv_fallback_expression, чтобы определить, использует ли запрос традиционный движок выполнения (по умолчанию включён).
| Параметр | Описание |
|---|---|
matrix.enable_mxv_fallback_expression |
Определяет, следует ли при неподдерживаемых выражениях переключаться на традиционный движок выполнения. Включён по умолчанию |
set matrix.enable_mxv_fallback_expression to off;
Если параметр matrix.enable_mxv_fallback_expression отключён, а возникает следующая ошибка, это означает, что запрос содержит типы данных, выражения или запросы, которые текущая версия векторизованного движка не поддерживает.
not implemented yet
Hash Agg и Group Agg — это две конкретные реализации операторов агрегации, каждая из которых применима в своих сценариях. Hash Agg использует хеш-таблицу для агрегации, а Group Agg агрегирует данные по группам. Обычно оптимизатор выбирает подходящий оператор на основе статистических данных. Однако при неточной статистике или недостаточной оптимизации запроса может быть выбран неоптимальный путь.
Вот два GUC-параметра, помогающих анализировать и оптимизировать запросы:
| Параметр | Описание |
|---|---|
matrix.enable_mxv_aggregate |
Управляет включением функции Group Agg. Включена по умолчанию |
matrix.enable_mxv_hash_aggregate |
Управляет включением функции Hash Agg. Включена по умолчанию |
Существует четыре возможных комбинации:
matrix.enable_mxv_aggregate: принудительно используется Group Aggregation;matrix.enable_mxv_hash_aggregate: принудительно используется Hash Aggregation.В MARS2 данные хранятся в упорядоченном виде. При создании таблицы необходимо определить индекс для упорядочивания. Поля, участвующие в этом порядке, называются ключами сортировки. Ключ сортировки можно задать только один раз и нельзя изменить или удалить. Чтобы максимально использовать преимущества упорядоченности, рекомендуется выбирать в качестве ключа сортировки поля, часто используемые в фильтрации и обладающие хорошими фильтрующими свойствами.
MARS2 позволяет задать набор ключей сортировки с помощью следующего SQL:
CREATE INDEX ON t USING mars2_btree (ci, cj, ck...);
Выбор ключей сортировки критически важен для производительности запроса:
Например, данные упорядочены по полям c1 и c2.
Только запросы с сортировкой:
SELECT * FROM t ORDER BY c1, c2;
SELECT * FROM t ORDER BY c1, c3;
Первый запрос больше не требует сортировки — векторизованный движок выполнения оптимизирует оператор сортировки. Во втором запросе c1 уже отсортирован, поэтому движок выполнения применяет специальную оптимизацию: сортирует только различные значения c3 внутри каждой группы c1.
Только запросы с группировкой:
SELECT sum(c1), sum(c2) FROM t GROUP BY c1, c2;
SELECT sum(c1), sum(c3) FROM t GROUP BY c1, c3;
Если используется Group Agg, производительность значительно возрастает аналогично сортировке: достаточно последовательного сканирования данных для агрегации. Для Hash Agg порядок данных почти не влияет на производительность. Как упоминалось ранее, векторизованный движок максимально эффективен для последовательных операторов, поэтому Group Agg чаще всего быстрее для вышеуказанных запросов, особенно для первого.
В итоге: необходимо анализировать бизнес-логику и выбирать ключи сортировки на основе характеристик запросов (столбцы, требующие сортировки, агрегации и фильтрации).
На основе ключей сортировки данные в MARS2 хранятся упорядоченно. Непрерывный упорядоченный фрагмент данных называется Run. Метаданные Run содержат минимальное и максимальное значения, используемые для фильтрации при запросах.
Поскольку фильтрация происходит на основе метаданных, сами данные не загружаются, что снижает I/O-нагрузку по сравнению с последовательным сканированием (сначала загрузка данных, затем фильтрация) и ускоряет фильтрацию. При создании таблиц в MARS2 минимакс-индекс по умолчанию не записывается — его необходимо явно объявить.
Минимакс-индекс не только позволяет движку хранения выполнять фильтрацию блоков, но и ускоряет вычисления векторизованного движка. Примеры его применения:
Сначала создайте минимакс-индекс на всех столбцах таблицы MARS2 (в реальных задачах индекс можно создавать по необходимости):
CREATE TABLE fast_filter (
tag int encoding (minmax),
ts timestamp encoding (minmax),
name text encoding (minmax),
region int encoding (minmax)
) USING MARS2;
CREATE INDEX ON fast_filter USING mars2_btree(tag);
Нам нужно запросить данные за определённый регион в этом году:
SELECT * FROM fast_filter WHERE ts > '2022-01-01' AND region = 2;
С точки зрения движка хранения: если максимальное значение поля ts в блоке (несколько строк, содержащих данные одного столбца) меньше 2022-01-01, движок хранения не загружает этот блок, экономя ресурсы I/O и снижая вычислительную нагрузку.
Векторизованный движок выполнения ускоряет вычисления, используя минимакс-информацию. Например, если минимальное и максимальное значения определённого региона оба равны 2, движок применит предикат ts > '2022-01-01' только для фильтрации подходящих данных, полностью пропуская операции, связанные с регионом, для повышения производительности.
Минимакс-индекс и ключи сортировки настраиваются независимо: минимакс-индекс может применяться ко всем столбцам, тогда как ключи сортировки обычно выбираются для нескольких столбцов. Их влияние на операторы фильтрации и сортировки различно, но существует пересечение — поэтому рекомендуется комплексно использовать оба механизма, чтобы максимально раскрыть их потенциал.
MARS2 поддерживает сканирование по индексу, но текущая версия векторизованного движка выполнения подключена только к минимакс-индексу и последовательному сканированию, но не к индексному сканированию. Поэтому для некоторых запросов, даже при включённом векторизованном движке, в плане выполнения может появиться текст Custom Scan (sortheapscan).
В этом случае можно включить векторизованный движок, отключив сканирование по индексу:
set enable_indexscan to off;
Подробнее см. Движок хранения