Greenplum: распределение по сегментам
DISTRIBUTED BY - решение №1 любой GP-таблицы, и вопрос «как выберешь ключ дистрибуции» - сердце GP-собеса. Два критерия конкурируют: локальность джойнов и равномерность.
// Смена ключа - полная перекладка таблицы: решение принимается при проектировании, «потом поправим» не работает.
Три способа разложить таблицу
DISTRIBUTED BY (hash): строки раскладываются по сегментам хешем ключа. Правильный ключ даёт локальные джойны и ровную нагрузку.
DISTRIBUTED RANDOMLY - равномерно, но без всякой co-location: годится для staging и таблиц без стабильного ключа джойна. DISTRIBUTED REPLICATED - полная копия на каждом сегменте: маленькие справочники джойнятся локально с чем угодно; для больших таблиц - запрещённый приём.
// Co-location - главный приз: две таблицы, соединяемые по своему ключу дистрибуции, джойнятся локально, без перегонок по сети.
- co-location
- джойн по ключу дистрибуции обеих таблиц - локален
- REPLICATED
- копия на каждом сегменте; только справочники
Skew: перекос данных и обработки
Равномерность обязательна: перекошенный ключ - статус, страна, NULL'ы - собирает данные на одном сегменте, и он пашет за всех. Все NULL хешируются в один сегмент - дистрибуция по колонке с NULL'ами это гарантированный горб.
Data skew проверяется SQL'ем: count(*) по gp_segment_id, gp_toolkit.gp_skew_coefficients; перекос от 10-20% - повод менять ключ.
// Processing skew коварнее: данные ровные, но GROUP BY или джойн по перекошенному значению собирает обработку в одном месте - виден только в рантайме.
- data / processing skew
- перекос хранения / перекос обработки в рантайме
Выбор ключа как компромисс
Идеальный ключ дистрибуции: высокая кардинальность (равномерность), участвует в главных джойнах (локальность), без NULL'ов. Обычно это id сущности-центра схемы: user_id, order_id.
Дистрибуция по дате у растущей таблицы фактов - антипаттерн: свежие данные всегда на одном сегменте, и «сегодняшние» запросы пашут на 1/N кластера.
// Конфликт «джойны просят один ключ, равномерность - другой» решается в пользу главного джойна, а равномерность проверяется фактом.
Как отвечать: «Как выберешь ключ дистрибуции для таблицы фактов?»
По двум критериям сразу. Первый - джойны: ключ должен совпадать с ключом дистрибуции таблиц, с которыми факты чаще всего соединяются, тогда джойн локален, без motion по сети; обычно это id центральной сущности вроде user_id. Второй - равномерность: высокая кардинальность, без NULL'ов - все NULL уезжают в один сегмент. После загрузки проверяю фактом: count(*) по gp_segment_id, перекос больше 10-20% - меняю ключ. Дату не беру никогда - свежие данные лягут на один сегмент. Справочники - REPLICATED, staging без стабильных джойнов - RANDOMLY. И помню: смена ключа - полная перекладка, это решение проектирования.
Оба критерия, проверка фактом и три готовых паттерна - решение, а не перечисление опций.
На чём валят
- −Дистрибуция по колонке с NULL'ами/низкой кардинальностью - все NULL на одном сегменте.
- −Джойн больших таблиц по разным ключам дистрибуции - motion всей таблицы.
- −REPLICATED для таблицы на сотни миллионов строк.
- −Не проверить skew после загрузки: «кластер медленный», а пашет один сегмент.
- −Дистрибуция по дате - свежие данные всегда на одном сегменте.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 13, остальные разбираются в тренажёре.
- Когда таблицу объявляют DISTRIBUTED RANDOMLY?A)Когда нужно, чтобы строки с одинаковым ключом попадали на один и тот же сегментB)Когда таблицу часто джойнят по конкретному столбцу и важна локальность джойнаC)Нет удачного ключа/редкие джойны → равномерное случайное распределениеD)По умолчанию для больших таблиц, так как случайное распределение самое быстрое
показать ответ и разбор
+C)Нет удачного ключа/редкие джойны → равномерное случайное распределение// разбор: DISTRIBUTED RANDOMLY раскидывает строки по сегментам случайно (round-robin-подобно), гарантируя равномерность независимо от данных. Берут, когда нет столбца-хорошего ключа (любой даёт перекос) и таблицу не джойнят регулярно по определённому полю. Минус: любой джойн по такой таблице требует перераспределения (redistribute) или broadcast, ведь связанные строки не co-located. Поэтому для часто джойнимых больших таблиц random — плохой выбор; там подбирают хеш-ключ под джойны.
- Что делает DISTRIBUTED REPLICATED и для каких таблиц это уместно?A)Реплицирует таблицу на mirror-сегменты ради отказоустойчивости, как это делает механизм зеркалB)Распределяет строки таблицы случайно и равномерно по всем сегментам без ключа распределенияC)Подходит в первую очередь для самых больших факт-таблиц кластера ради ускорения их чтенияD)Копия таблицы на каждом сегменте — локальные джойны с мелким справочником
показать ответ и разбор
+D)Копия таблицы на каждом сегменте — локальные джойны с мелким справочником// разбор: REPLICATED-таблица не имеет ключа распределения — её полная копия лежит на каждом сегменте. Смысл — маленькие часто джойнимые измерения/справочники: раз копия есть на каждом сегменте, джойн большой распределённой таблицы с ней идёт локально, без перераспределения или broadcast в рантайме. Это заранее оплаченный broadcast. Годится только для небольших таблиц: для крупных репликация на все сегменты пожирает место и замедляет запись (каждая вставка идёт на все сегменты).
- Как выбирают хороший ключ распределения таблицы в Greenplum?A)Равномерный + совпадающий с ключом джойнов; баланс двух целейB)Берут столбец самой низкой кардинальности (например, булев флаг), чтобы сегментов задействовать меньшеC)Ключ распределения выбирать не нужно — Greenplum сам обеспечивает идеальную равномерностьD)Берут тот же столбец, что и первичный ключ, независимо от того, как таблицу джойнят
показать ответ и разбор
+A)Равномерный + совпадающий с ключом джойнов; баланс двух целей// разбор: Хороший ключ распределения удовлетворяет двум вещам сразу. Равномерность: высокая кардинальность и отсутствие доминирующих значений/NULL, иначе один сегмент перегружен (data skew), и запрос идёт со скоростью самого медленного сегмента. Co-location: если распределить джойнимые таблицы по общему ключу джойна, соединение идёт локально на сегментах без перераспределения. Эти цели часто конфликтуют (равномерный ключ ≠ ключ джойна), и приходится выбирать приоритет по нагрузке. Никогда не берут ключ с большой долей NULL или сильным перекосом.
- Один сегмент хранит втрое больше строк, чем остальные, и запросы тормозят. Что это и почему?A)Это нормальная работа MPP: неравномерность по сегментам не влияет на скорость выполнения запросовB)Data skew из-за плохого ключа распределения: перекошенный сегмент — узкое место, запрос идёт со скоростью самого нагруженногоC)Проблема в нехватке памяти координатора, а распределение данных по сегментам тут ни при чёмD)Достаточно добавить в кластер новые сегменты — перекос исчезнет сам без смены ключа распределения
показать ответ и разбор
+B)Data skew из-за плохого ключа распределения: перекошенный сегмент — узкое место, запрос идёт со скоростью самого нагруженного// разбор: Это data skew — неравномерное распределение из-за ключа с доминирующими значениями, большой долей NULL или низкой кардинальностью (хеш кладёт непропорционально много строк на один сегмент). MPP работает со скоростью самого медленного сегмента: перегруженный обрабатывает свою гору данных, пока остальные простаивают, — параллелизм теряется. Диагностика — count по gp_segment_id. Лечение: сменить ключ распределения на более равномерный (иногда добавить составной ключ) или, если равного нет, DISTRIBUTED RANDOMLY.
- Что такое co-location таблиц в Greenplum и зачем она нужна?A)Co-location означает физическое хранение всех таблиц кластера на одном общем выделенном сегментеB)Co-location — это репликация обеих джойнимых таблиц целиком на все сегменты кластера сразуC)Общий ключ распределения → локальный джойн без перераспределенияD)Co-location ускоряет запись данных в таблицы, а на стоимость джойнов не влияет
показать ответ и разбор
+C)Общий ключ распределения → локальный джойн без перераспределения// разбор: Co-location — таблицы распределены по одному и тому же ключу, по которому их джойнят: тогда строки с совпадающим ключом гарантированно лежат на одном сегменте, и соединение выполняется локально на каждом сегменте без обмена строками по сети (motion). Это резко дешевле, чем redistribute/broadcast больших таблиц. Поэтому ключ распределения крупных часто джойнимых таблиц подбирают под их общий ключ джойна. Если распределения не совпадают, планировщик вынужден перераспределять данные в рантайме — главный источник дороговизны джойнов в MPP.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.