Обзор

MARS3 Bucket — это механизм оптимизации параллельного выполнения на уровне хранения, разработанный YMatrix для сценариев параллельного сканирования в MPP-архитектурах. Во время записи данные организуются в несколько логических бакетов на основе хеш-значений ключа распределения. Это гарантирует, что данные с одинаковым ключом распределения будут обрабатываться одним и тем же рабочим процессом при параллельном сканировании. Такой подход сохраняет семантику распределения данных (locus), устраняет ненужную перераспределку данных (Motion) и обеспечивает переход от «более быстрого сканирования» к «более локальным вычислениям».

Основные преимущества

  • Снижение объёма ненужной передачи данных
    Предотвращает дополнительные операции Motion, вызванные параллельным сканированием. В тестах TPCH S100 и S1000 производительность запросов возрастает примерно в два раза.
  • Сокращение числа срезов и сложности выполнения
    Уменьшает количество срезов выполнения (Slices), снижая накладные расходы на планирование в системе.
  • Раскрытие потенциала параллелизма
    Расширяет параллелизм за пределы уровня сканирования, позволяя эффективнее использовать его преимущества на всём пути выполнения запроса.

Этапы выполнения с использованием Bucket

Цель MARS3 Bucket — сохранить строгую локальность данных после параллельного сканирования, чтобы максимум вычислений выполнялся локально.

Помимо традиционного распределения, которое определяет, на каком узле хранятся конкретные данные, MARS3 Bucket дополнительно организует данные внутри каждого узла в структурированные бакеты. Это гарантирует, что данные из одного бакета будут выдаваться одним рабочим процессом.

Основное отличие подхода MARS3 Bucket от стандартного параллельного сканирования с прерыванием по страницам заключается в упорядоченности обработки внутри segment. Параллельное сканирование переходит от простого одновременного чтения данных несколькими рабочими процессами к совместному чтению данных в соответствии с семантикой распределения.

Image

Рассмотрим таблицу t_sales с ключом распределения c1. Выполняется следующий SQL-запрос: select c1, count(*) from t_sales group by c1;

Режим без Bucket (параллельный сценарий)

В стандартном параллельном сценарии (без режима Bucket) план выполнения выглядит так:

Gather Motion 12:1
  -> Finalize HashAggregate
       Group Key: c1
       -> Redistribute Motion 12:12
            Hash Key: c1
            -> Partial HashAggregate
                 Group Key: c1
                 -> Parallel Seq Scan on t_sales
  1. Параллельное последовательное сканирование: каждый Segment запускает несколько рабочих процессов для параллельного чтения данных. Однако процессы случайным образом конкурируют за страницы. В результате нет гарантии, что данные с одинаковым значением c1 будут обработаны одним рабочим процессом.
  2. Частичная хеш-агрегация: каждый рабочий процесс выполняет первоначальную агрегацию только над своими данными.
  3. Redistribute Motion: поскольку одно и то же значение c1 может оказаться у нескольких рабочих процессов даже после частичной агрегации, данные необходимо перераспределить по c1, чтобы обеспечить корректность финальной агрегации.

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

Режим MARS3 Bucket

При использовании MARS3 Bucket план выполнения упрощается:

Gather Motion 12:1                                                                                                                                                                  
   ->  HashAggregate                                                                                                                                                                                             
         Group Key: c1                                                                                                                                                                                                                                      
         ->  Parallel Custom Scan (MxVScan)                                                                                                                                              
  1. Организация данных: на этапе записи данные хешируются и группируются в бакеты.
  2. Совместное сканирование: на этапе сканирования каждый рабочий процесс читает только один или несколько конкретных бакетов. Это гарантирует, что выходные данные сканирования сохраняют характеристики хеш-распределения и соответствуют семантике распределения.
  3. Результат: поскольку данные остаются правильно распределёнными, плану выполнения не требуется явный оператор Motion. Это значительно повышает эффективность выполнения SQL-запроса.

Связанные понятия

Совместная локальность данных (Data Co-locality)

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

Параллельное сканирование

С точки зрения всей таблицы, YMatrix использует MPP-архитектуру, где процессы сканируют данные на каждом Segment. Такой уровень параллелизма называется параллелизмом на уровне экземпляра.

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