Производственный Hadoop-запрос, который занимает много времени - PullRequest
1 голос
/ 09 апреля 2019

Текущий статус

У нас есть запрос, который выполняется в течение 2+ часов.При рассмотрении хода выполнения запрос тратит много времени во время объединения с таблицей T5 и на заключительном этапе запроса.Есть ли способ, которым мы можем упростить что-то сделать с этим запросом?Мне не удалось использовать агрегатные функции вместо rank (), так как используемый orderby немного сложен.

То, что мы уже попробовали

Мы уже преобразовали подзапросов в case операторов в предложении select и помогли сократить время выполнения, но это не было значительным.Мы упростили связанный запрос для T3, T4 и T6.

SELECT * FROM 
        (SELECT T2.f1, T2.f2 .... T5.f19, T5.f20, 
                   case when T1.trxn_id is null then T2.crt_ts
                        when T1.trxn_id is not null and T5.acct_trxn_id is not null and T2.crt_ts >= T5.crt_ts then T2.crt_ts
                        when T1.trxn_id is not null and T5.acct_trxn_id is not null and T2.crt_ts < T5.crt_ts then T5.crt_ts
                    end as crt_ts , 
                    row_number() over ( partition by T2.w_trxn_id,
                                            if(T1.trxn_id is null, 'NULL', T1.trxn_id)
                                            order by T2.business_effective_ts desc,
                                            case when T1.trxn_id is null then T2.crt_ts
                                            when T1.trxn_id is not null and T5.acct_trxn_id is not null and T2.crt_ts >= T5.crt_ts then T2.crt_ts
                                            when T1.trxn_id is not null and T5.acct_trxn_id is not null and T2.crt_ts < T5.crt_ts then T5.crt_ts
                                            when T1.trxn_id is not null and T5.acct_trxn_id is null then T2.crt_ts end desc
                                        ) as rnk
                FROM(SELECT * FROM T3 WHERE title_name = 'CAPTURE' and tr_dt IN (SELECT tr_dt FROM DT_LKP))
                T2
                LEFT JOIN (SELECT * FROM T6 WHERE tr_dt IN (SELECT tr_dt FROM DT_LKP)) 
                T1 ON T2.w_trxn_id = T1.w_trxn_id AND T2.business_effective_ts = T1.business_effective_ts
                LEFT JOIN (SELECT f1, f3. ... f20 FROM T4 WHERE tr_dt IN (SELECT tr_dt FROM DT_LKP)) 
                T5 ON T1.trxn_id = T5.acct_trxn_id
                WHERE if(T1.trxn_id is null, 'NULL', T1.trxn_id) = if(T5.acct_trxn_id is null, 'NULL', T5.acct_trxn_id)
        ) FNL WHERE rnk = 1

1 Ответ

2 голосов
/ 09 апреля 2019

Не уверен, что это вам сильно поможет. Есть довольно странное предложение WHERE:

WHERE if(T1.trxn_id is null, 'NULL', T1.trxn_id) = if(T5.acct_trxn_id is null, 'NULL', T5.acct_trxn_id)

Это, вероятно, для объединения NULL с нормальными значениями. Тогда это не работает, потому что Прежде всего, условие соединения - T5 ON T1.trxn_id = T5.acct_trxn_id, это означает, что NULL не объединяются, затем WHERE работает как фильтр после объединения. Если T5 не присоединено, то T5.acct_trxn_id преобразуется в строку 'NULL' в WHERE и сравнивается со значением NOT NULL T1.trxn_id и, скорее всего, отфильтровывается, в этом случае работает как INNER JOIN. Если это происходит, T1.trxn_id имеет значение NULL (управляющая таблица), он преобразуется в строку 'NULL' и сравнивается со всегда строкой 'NULL' (потому что в любом случае не присоединяется согласно предложению ON), и такая строка пропускается (хотя я не проверял ее, хотя ). Логика выглядит странно, и я думаю, что она не работает так, как задумано, или конвертирована в INNER. Если вы хотите объединить все, включая NULL, переместите это WHERE в предложение JOIN ON.

Если имеется много строк с NULL, то объединение с NULL с использованием подстановки со строкой 'NULL' умножит строки и приведет к дублированию.

На самом деле, при расследовании плохой работы JOIN, проверьте две вещи:

  1. Ключи объединения не дублируются, или ожидается дублирование
  2. Ключи соединения (а также разбиение по столбцам в row_number) не перекошены, см. Это: https://stackoverflow.com/a/53333652/2700344 и это: https://stackoverflow.com/a/51061613/2700344

Если все выглядит хорошо, тогда настройте правильный параллелизм редуктора, уменьшите hive.exec.reducers.bytes.per.reducer, чтобы запустить больше редукторов

Также максимально уменьшите DT_LKP, даже если вы знаете, что он содержит некоторые даты, которые определенно не являются / не должны быть в действительности таблицами, используйте CTE для его фильтрации, если это возможно.

Также немного упростите логику (это не улучшит производительность, но упростит код). Дело в выборе:

when T1.trxn_id is not null and T5.acct_trxn_id is not null and T2.crt_ts >= T5.crt_ts then T2.crt_ts
when T1.trxn_id is not null and T5.acct_trxn_id is not null and T2.crt_ts < T5.crt_ts then T5.crt_ts

<=>

else greatest(T2.trxn_id,T5.crt_ts)

Если T5.crt_ts равен нулю, ваш оператор case вернет ноль, great () также вернет ноль

Упрощенный оператор CASE в row_number:

case when case when (T1.trxn_id is null) or (T5.acct_trxn_id is null) then T2.crt_ts
     else greatest(T2.trxn_id,T5.crt_ts)
 end

Также это: if(T1.trxn_id is null, 'NULL', T1.trxn_id) <=> NVL(T1.trxn_id,'NULL')

Конечно, это только предложения, я их не проверял

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...