Нужна помощь в переписывании этого запроса - PullRequest
1 голос
/ 26 апреля 2019

У нас есть этот запрос в производстве, который выполняется ежедневно Это делает много объединений, а также использует оконную функцию в улье

Мы пытались добавить несколько параметров, но это не сильно помогло

Структура примерно такая -

SELECT
        C.f1, C.f2, A.f2 ...
FROM (
    SELECT * FROM (
        SELECT T1.*, B.atid, B.a_id,
        ROW_NUMBER() OVER (PARTITION BY T1.wtid, B.atid ORDER BY T1.b_ts DESC) AS RANK_
        FROM T1 AS T1
        JOIN T5 ON T1.t_dt = T5.t_dt
        JOIN T2 B ON T1.wtid = B.wtid and T1.b_ts = B.b_ts
        LEFT OUTER JOIN (SELECT p_cd FROM T3 WHERE PV_TY_CD = 'ORIG_CD') PV
        ON T1.TYP = PV.p_cd
        WHERE T1.state not in ("INVALID")
        AND T1.evt_name NOT IN ('INACTIVE','DORMANT')
        AND ISNULL(PV.p_cd)
    ) T
    WHERE T.rank_ = 1
) A

JOIN (SELECT *, row_number() over (partition by ac_id order by b_ts desc) rank_  
      FROM T4
      WHERE event not in ('CT','UPD')
     ) AS C
  ON A.a_id = C.a_id
AND A.atid = C.ac_id
AND C.rank_ = 1
JOIN T6 ON C.t_dt = T6.t_dt
  • Поскольку я не могу игнорировать какие-либо таблицы (и объединения), мой подход состоял в том, чтобы заменить оконную функцию другим объединением, используя агрегатную функцию max, но я не смог переписать ее.
  • Кроме того, я не уверен, что это, безусловно, поможет улучшить производительность, поэтому любое руководство поможет нам.

1 Ответ

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

Аналитические функции обычно работают лучше, чем объединения с select max, потому что в случае аналитической функции вы читаете одну и ту же таблицу только один раз, а вычисление row_number распределяется по секциям.

Попробуйте перегруппировать объединения и фильтрацию.

Соедините

LEFT OUTER JOIN (SELECT p_cd FROM T3 WHERE PV_TY_CD = 'ORIG_CD') PV
        ON T1.TYP = PV.p_cd

, где условие ISNULL(PV.p_cd) сокращает некоторые строки в T1.То же самое делают эти условия:

WHERE T1.state not in ("INVALID")
        AND T1.evt_name NOT IN ('INACTIVE','DORMANT')

Переместите это объединение в подзапрос, если он фильтрует lo, это может помочь уменьшить набор данных в T1 до всех других объединений и row_number ():

(select T1.* from T1 
             left join (SELECT p_cd FROM T3 WHERE PV_TY_CD = 'ORIG_CD') PV 
                       ON T1.TYP = PV.p_cd 
 where T1.state not in ("INVALID")
        AND T1.evt_name NOT IN ('INACTIVE','DORMANT')
        AND ISNULL(PV.p_cd)
) as T1 

Кроме того, первый номер строки вычисляется только для таблиц T1 и B:

PARTITION BY T1.wtid, B.atid ORDER BY T1.b_ts DESC

Рассмотрите возможность объединения таблицы T5 после фильтра row_number, если это объединение имеет большой вес, а фильтр row_number уменьшает набор данных, затем переноситеrow_number с фильтром в подзапросе снова и присоединение к подзапросу, отфильтрованному с помощью T5.

(--filtered by row_number
select * from
(
 SELECT T1.*, B.atid, B.a_id,
        ROW_NUMBER() OVER (PARTITION BY T1.wtid, B.atid ORDER BY T1.b_ts DESC) AS RANK_
  from
    (select T1.* from T1 
                 left join (SELECT p_cd FROM T3 WHERE PV_TY_CD = 'ORIG_CD') PV 
                           ON T1.TYP = PV.p_cd 
     where T1.state not in ("INVALID")
            AND T1.evt_name NOT IN ('INACTIVE','DORMANT')
            AND ISNULL(PV.p_cd)
    ) as T1 JOIN T2 B ON T1.wtid = B.wtid and T1.b_ts = B.b_ts
) T WHERE T.rank_ = 1
) T --filtered
JOIN T5 ON T1.t_dt = T5.t_d  

Это может помочь в зависимости от ваших данных.

Читайте также: https://stackoverflow.com/a/51061613/2700344 и это: https://stackoverflow.com/a/51061613/2700344

...