NTILE функция производительности в улье - PullRequest
0 голосов
/ 07 апреля 2020

Есть ли способ оптимизировать время выполнения функции NTILE. В настоящее время у нас есть около 51 млн записей с 17 переменными. Мы выполняем запрос ниже, чтобы разделить наборы данных на 100 сегментов.

create table secondary_table  
stored as orc 
as
select a.*,NTILE(100) OVER(ORDER BY score) AS score_rank
from main_table a;

Здесь переменная Score представляет 12 десятичных значений git.

На данный момент вся нагрузка сбрасывается на один редуктор, который занимает много времени после завершения 99%. Есть ли какой-то подход, который мы можем оптимизировать, так как текущий запрос занимает около 35 минут. выполнить.

Ценю любой ответ.

Заранее спасибо.

1 Ответ

0 голосов
/ 07 апреля 2020

Это не совсем ответ, но он может дать некоторые рекомендации.

Проблема заключается в отсутствии partition by в оконной функции. Замена его эквивалентными конструкциями с использованием, скажем, row_number() и count(*) не поможет.

Когда я столкнулся с этим, я смог обойти его одним из двух способов.

  • Если имеется много дубликатов, агрегируйте и используйте совокупные суммы для определения плиток.
  • В противном случае разбейте значения на группы.

В качестве примера второй. Предполагая, что оценки варьируются от 0 до 1000, с довольно равномерным распределением. Тогда:

select t.*,
       1 + floor((t.seqnum_within + tt.running_cnt - tt.cnt - 1) * 100 / cnt)
from (select t.*,
             row_number() over (partition by trunc(score) order by score) as seqnum_within
      from t
     ) t join
     (select trunc(score) as score_trunc, count(*) as cnt,
             sum(count(*)) over (order by min(score)) as running_cnt,
             sum(count(*)) over () as total_cnt
      from t
      group by trunc(score)
     ) tt
     on trunc(t.score) = score_trunc;

GROUP BY и JOIN должны лучше использовать параллельное оборудование.

...