сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Greenplum

Motion и выполнение

Зачем это спрашивают

Motion - валюта, которой GP платит за распределённость: перегонки данных между сегментами. Чтение EXPLAIN через motion'ы - навык, который отличает GP-практика от постгресиста в гостях.

// Идеальный план тяжёлого джойна - ноль motion: всё локально благодаря co-location.

Redistribute, Broadcast, Gather

Redistribute Motion - перехеширование строк по ключу операции: обе стороны джойна переезжают к «своим». Broadcast Motion - рассылка таблицы целиком всем сегментам: выгодна для малой стороны.

Оптимизатор выбирает между ними по оценкам строк, и потому устаревшая статистика опасна вдвойне: broadcast, назначенный «гиганту», взрывает interconnect.

// Gather Motion - сборка результата на мастере: нормален для финальных тысяч строк; миллионы строк через Gather - запрос спроектирован неверно.

redistribute / broadcast
перехеширование по ключу / рассылка таблицы всем
gather
сборка на мастере; для компактных результатов

EXPLAIN, статистика и двухфазные агрегаты

EXPLAIN в GP читается через motion'ы: их число и объём - главная статья расходов. Число слайсов плана = число motion + 1; каждый слайс - свои процессы на каждом сегменте.

GROUP BY не по ключу дистрибуции - двухфазный: локальная агрегация на сегментах → redistribute по ключу группировки → финальная. Локальная фаза режет сетевой трафик - оптимизатор делает это сам, но по статистике.

// ANALYZE в MPP (massively parallel processing) критичен вдвойне: свежезагруженная таблица без него планируется вслепую. ORCA (GPORCA) - оптимизатор сложных аналитических планов - живёт на оценках кардинальности.

двухфазная агрегация
локальная на сегментах → redistribute → финальная

Память и спиллы

Память запроса ограничена (statement_mem, resource groups): не хватило - спилл на диск (workfiles). Запрос доезжает, но на порядок медленнее; мониторинг gp_workfile_* показывает, кто спиллит.

DISTINCT и GROUP BY по высококардинальному ключу без памяти - спиллы на всех сегментах разом.

// UPDATE/DELETE мелкими порциями - отдельная беда: MVCC (multiversion concurrency control) пухнет, мёртвые строки копятся, а VACUUM по ним ходит вечно.

spill / workfiles
не влезло в память - на диск; на порядок медленнее

Как отвечать: «Как прочитаешь EXPLAIN тяжёлого запроса в Greenplum?»

Сначала ищу motion'ы это главная статья расходов плана. Смотрю их тип и объём: Broadcast на большой таблице - красный флаг, обычно значит устаревшую статистику, лечится ANALYZE; Redistribute обеих сторон джойна - вопрос, нельзя ли добиться co-location ключом дистрибуции. Затем Gather: миллионы строк на мастер - запрос спроектирован неверно, агрегировать надо до сборки. Дальше сверяю оценки строк с ожиданиями - MPP-план строится на кардинальностях. И если запрос всё равно медленный при хорошем плане - смотрю спиллы в gp_workfile_*: нехватка памяти замедляет на порядок молча.

Чтение плана в правильном порядке приоритетов с лечением каждой находки - рабочий процесс GP-инженера.

На чём валят

  • Не заметить Broadcast таблицы на миллиард строк в EXPLAIN.
  • Свежезагруженная таблица без ANALYZE - оптимизатор вслепую.
  • SELECT миллионов строк «посмотреть» - Gather душит мастер.
  • DISTINCT по высококардинальному ключу без памяти - спиллы на всех сегментах.
  • UPDATE/DELETE мелкими порциями - MVCC пухнет (см. VACUUM).

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #gp_motion_exec1 / 5
    Когда в плане появляется redistribute motion и почему он дорог?
    A)Redistribute появляется при каждом запросе и стоит примерно столько же, сколько чтение с диска
    B)Redistribute перемещает строки внутри одного сегмента, поэтому сеть при нём не задействуется
    C)Обмен по новому ключу для не-co-located джойна; много данных по сети
    D)Это дешёвая операция, ведь Greenplum пересылает между сегментами лишь метаданные, а не сами строки
    показать ответ и разбор
    +C)Обмен по новому ключу для не-co-located джойна; много данных по сети

    // разбор: Redistribute motion возникает, когда операция требует, чтобы строки с одинаковым ключом были на одном сегменте, а таблица распределена по другому ключу (джойн по не-ключу распределения, GROUP BY не по ключу). Тогда сегменты по interconnect пересылают строки, перехешируя по нужному ключу, — фактически перекладывают большую часть таблицы по сети. Это дорого: сеть + сериализация + возможный перекос после переклада. Устраняется co-location (общий ключ распределения) или репликацией мелкой стороны, чтобы redistribute больших таблиц не понадобился.

  2. #gp_motion_exec2 / 5
    Что делает broadcast motion и когда планировщик его выбирает?
    A)Broadcast перераспределяет обе большие таблицы по новому ключу поровну между всеми сегментами
    B)Broadcast собирает все строки обеих таблиц на координатор и джойнит их там централизованно
    C)Broadcast применяют, когда обе стороны джойна очень большие, чтобы разослать их целиком повсюду
    D)Рассылает копию (обычно маленькой) таблицы на все сегменты, чтобы джойн шёл локально; выгоден, когда одна сторона мала
    показать ответ и разбор
    +D)Рассылает копию (обычно маленькой) таблицы на все сегменты, чтобы джойн шёл локально; выгоден, когда одна сторона мала

    // разбор: Broadcast motion отправляет полную копию одной стороны джойна на все сегменты. Планировщик выбирает его, когда эта сторона мала (меньше порога): дешевле разослать маленькую таблицу всем, чем перераспределять обе большие (redistribute). После broadcast каждый сегмент джойнит свою часть большой таблицы с полной копией маленькой локально. Аналог broadcast join в Spark. Опасность — если «маленькая» на деле велика (плохая оценка статистики): рассылка большого объёма на все сегменты дороже redistribute. Отсюда важность актуальной ANALYZE-статистики.

  3. #gp_motion_exec3 / 5
    Что такое slice (срез) в плане запроса Greenplum?
    A)Часть плана между motion-операциями, которую сегменты выполняют параллельно; план режется на срезы в каждой точке motion
    B)Slice — это горизонтальный фрагмент таблицы (набор строк), обрабатываемый отдельным запросом
    C)Slice — это одна партиция таблицы, к которой обращается запрос после отсечения остальных
    D)Slice — это резервная копия плана запроса, используемая при сбое основного исполнения
    показать ответ и разбор
    +A)Часть плана между motion-операциями, которую сегменты выполняют параллельно; план режется на срезы в каждой точке motion

    // разбор: План распределённого запроса делится на срезы (slices) — по срезу с каждой стороны каждого motion. Внутри среза сегменты работают независимо и параллельно над своими данными, а границы срезов — это точки обмена строками (motion). Число срезов и процессов на сегмент растёт с числом motion; каждый сложный запрос с несколькими перераспределениями порождает много срезов, потребляющих память и слоты. Понимание срезов помогает читать EXPLAIN (видно, где план «разрезан» обменом) и объясняет, почему обилие motion увеличивает расход ресурсов.

  4. #gp_motion_exec4 / 5
    Где в выводе EXPLAIN Greenplum обычно находятся motion-узлы и о чём они сигналят?
    A)В самом низу плана; motion выполняется первым, ещё до чтения данных с дисков сегментов
    B)Ближе к вершине плана; их наличие и объём показывают, сколько данных гоняется между сегментами — главную цену запроса
    C)Motion-узлов в EXPLAIN Greenplum встречается редко, план ничем не отличается от обычного PostgreSQL
    D)Motion-узлы показывают лишь порядок вывода строк и на стоимость запроса никак не указывают
    показать ответ и разбор
    +B)Ближе к вершине плана; их наличие и объём показывают, сколько данных гоняется между сегментами — главную цену запроса

    // разбор: В EXPLAIN распределённого плана motion-узлы (Gather/Redistribute/Broadcast Motion) обычно располагаются ближе к вершине — данные снизу считаются на сегментах, а наверху перемещаются. Читая план, смотрят прежде всего на motion: их тип и оценённый объём говорят, сколько строк уйдёт по interconnect — а это чаще всего и есть узкое место распределённого запроса. Много Redistribute/Broadcast больших объёмов — сигнал плохой co-location или неудачного распределения. Оптимизация MPP-запроса во многом сводится к тому, чтобы убрать или удешевить motion.

  5. #gp_motion_exec5 / 5
    Почему джойн двух больших таблиц по их общему ключу распределения дешевле, чем по произвольному столбцу?
    A)По ключу распределения джойн дешевле потому, что по нему построен уникальный индекс
    B)Разницы нет: сегменты в обоих случаях обмениваются строками через interconnect одинаково
    C)По ключу распределения они co-located — джойн локален на сегментах без motion; по другому столбцу нужен redistribute обеих
    D)Джойн по произвольному столбцу дешевле, так как не задействует ключ распределения таблиц
    показать ответ и разбор
    +C)По ключу распределения они co-located — джойн локален на сегментах без motion; по другому столбцу нужен redistribute обеих

    // разбор: Если обе большие таблицы распределены по столбцу, по которому их джойнят, совпадающие строки лежат на одном сегменте (co-location), и каждый сегмент джойнит свои локальные части без пересылки — motion не нужен. Джойн же по произвольному столбцу означает, что связанные строки разбросаны по разным сегментам, и планировщик обязан перераспределить (redistribute) одну или обе таблицы по этому столбцу через interconnect — большой сетевой обмен. Поэтому ключ распределения крупных таблиц подбирают под их частый ключ джойна, а не как попало.

дальше

Теорию прочитали. Навык ставится повторением

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