Skip to content

Index

Куратор раздела

Шустиков Владимир, оставивший военную жизнь позади и ушедший в данные с головой. Работаю с данными более 2х лет и останавливаться не собираюсь! Веду:

Telegram канал

Youtube канал

Если хочешь сменить текущую профессию на Дата Инженера — пиши не стесняйся, я сам проходил этот не легкий путь и тебе помогу https://t.me/ShustDE

Хочешь улучшить текущий раздел, внести недостающее или поправить формулировку? Предлагай PR и тегай @ShustGF.

Правила хорошего тона

1) Используйте только те колонки, которые вам необходимы. Не нужно в продовый запрос тыкать “SELECT *”, в 90% всех таблиц в ГП используется колоночное хранение(каждая колонка находится в отдельном файле), это в свою очередь ведет к поиску всех колонок.

2) Изучайте DDL таблиц перед тем как с ними работать. Обращайте внимание по какким полям таблица рапределена и партицирована. В фильтрах старайтесь указывать поля партицирования, чтобы уменьшить кол-во считываемых данных.

3) Чаще всего партиции строят на несколько месяцев-лет вперед, поэтому при фильтрации по дате партицирования обязательно ставте границу до сегодняшнего дня, в противном случае БД будет заходить в партиции, в которых нет данных.

where dt > '2025-05-01' and dt < current_timestamp()
where date between '2025-05-01' and current_date()

4) Не делайте бессмысленных преобразований типов данных.

where date_trunc('month', dt)::date < current_date  -- здесь и так округление до 00:00:00

5) Не преобразуйте колонки, по которым парцированы или распредлены таблицы, это приведет к новому перераспределению данных, а парции вообще использоваться не будут

6) Из фильтрации убирайте функции, они там не нужны. Если необходимо фильтрануться по пользовательской функции, находите ее текст(посмотреть скрипт можно тут и используйте только те условия, которые вам нужны, либо расчет выводите в отдельную темповую таблицу.

7) Не соединяйте таблицы не по ключам распределения. Старайтесь выводить данные таблицы в темповые, фильтровать их по максисуму, распределять по логике ваших дальнейших соединений.

8) Используйте предрасчитанные поля, так как нужно заново высчитывать значения поля

where dt + interval '3h' > curremt_timestamp - interval '7 day' -- левая чать не предрасчитана
where dt > curremt_timestamp - interval '7 day' - interval '3h' -- левая чать предрасчитана

9) Усли условие JOIN большое(3 и более условий) например

from t1 
  JOIN t2
    ON t1.col1 = t2.col1 and
       t1.col2 = t2.col2 and
       t1.col3 = t2.col3 and
       t1.col4 = t2.col4

лучше вынесите таблицы в темповую таблицу, захешируйте значения(но обращаю внимание hash(null) дает заначение, поэтому либо отфильтруйте их либо воспользуйтесь CASE) иначе соединится не то что нужно

11) group by и partition by делайте по полям дистрибуции

12) В GreenPlum нет наследование алиасов, не нужно копировать 10 преобразований одно и того же поля, выведите все в отдельное СТЕ и уже работайте от туда

13) В JOIN не указывайте поля соединения через OR, старайтесь уйти от этого

14) небольшие таблицы можно делать в дистрибуцией по Replicated это позволит быстрее обрабатывать JOIN в запросах

15) Не используйте plpgsql функций в теле запроса, это замендляет работу запроса

Кейсы

Кейс 1: Уходи от OR в JOIN'ах

Есть запрос в котором втречается JOIN с 3мя условиями. Таблицы имеют большое кол-во строк.

SELECT ...
FROM _tmp_calc_cred AS cc
    INNER JOIN _postback_api  as pa 
        ON cc.request_external_id = pa.EXTERNAL_ID OR
           cc.calculation_id = pa.EXTERNAL_ID  OR
           cc.request_id = pa.EXTERNAL_ID

Во первых в данном случе стоит рапледелить таблицу _tmp_calc_cred по всем сегментам, так как в JOIN используется 3 разные колонки, а таблицу _postback_api по ключу EXTERNAL_ID, чтобы запрос выполнялся параллельно на разных сегментах.

Данный запрос стоит преобразовать к следующиму виду:

select ...
  FROM alexd._tmp_CALCULATION_CREDIT AS cc
      INNER JOIN alexd._postback_api  as pa
            ON cc.request_external_id = pa.EXTERNAL_ID 
union all
  select ...
  FROM alexd._tmp_CALCULATION_CREDIT AS cc
      INNER JOIN alexd._postback_api  as pa
           ON cc.calculation_id = pa.EXTERNAL_ID
union
  select ...
  FROM alexd._tmp_CALCULATION_CREDIT AS cc
      INNER JOIN alexd._postback_api  as pa
           ON  cc.request_id = pa.EXTERNAL_ID

В первом случае выберится физический вид JOIN'а - Nested Loop, 2й запрос хоть и больше, но выберится Hash JOIN. Здесь главное по отдельности запустить запросы и пприкинуть, какое максимальное кол-во строк может получиться в результате. Если строк в результате получается больше, чем в самих таблицах (произошел CROSS JOIN данных), то возможно 1й вариант будет выстрее!