Рекурсивная таблица CTE - Расчет EWMA (EMA) - Как оптимизировать / реорганизовать этот код, чтобы TDWM не убивал его каждый раз? - PullRequest
1 голос
/ 16 июня 2020

Я создал запрос, который создает таблицы CTE, два из которых нерекурсивны, а один - рекурсивный, чтобы вычислить экспоненциально взвешенное скользящее среднее (EMA). Когда я запускаю свой код в Teradata, TDWM через какое-то время убивает его.

Есть идеи, как улучшить / обойти это?

WITH 

smooth AS (
    SELECT CAST(0.741870935 AS NUMERIC (20,5)) AS alpha
),

numbered AS (
    SELECT 
        ROW_NUMBER() OVER (ORDER BY customer_name, closed_date) as rn,  
        customer, 
        closed_date, 
        metric

    FROM my_table
),

recursive EWMA AS (
    SELECT rn, customer, closed_date, metric, CAST(metric AS NUMERIC(20,5)) as EWMA
    FROM numbered
    WHERE rn = 1

    UNION ALL

    SELECT numbered.rn, numbered.customer, numbered.closed_date, numbered.metric,
    smooth.alpha * numbered.metric + (1-smooth.alpha) * EWMA.EWMA
    FROM EWMA
    JOIN numbered
    ON EWMA.rn + 1 = numbered.rn
    CROSS JOIN smooth   
)

SELECT * FROM EWMA
ORDER BY closed_date;

1 Ответ

1 голос
/ 16 июня 2020

Вы пробовали установить поле depth для ограничения рекурсии? Что-то вроде:

WITH smooth AS (...),
numbered AS (...),
recursive EWMA AS (
  SELECT 
    rn, customer, closed_date, metric, CAST(metric AS NUMERIC(20,5)) as EWMA, 
    1 AS depth
  FROM numbered
  WHERE rn = 1

  UNION ALL

  SELECT 
    numbered.rn, numbered.customer, numbered.closed_date, numbered.metric,
    smooth.alpha * numbered.metric + (1-smooth.alpha) * EWMA.EWMA, 
    EWMA.Depth + 1 AS Depth
  FROM EWMA
  INNER JOIN numbered ON EWMA.rn + 1 = numbered.rn
  CROSS JOIN smooth   
  WHERE depth <= 10 -- Restrict recursion
)
SELECT * 
FROM EWMA
ORDER BY closed_date;

Рекурсивное соединение с numbered может вызывать проблему, если таблица my_table очень большая. В идеале вам нужно выполнить прямое соединение по равенству для столбцов PI, например table1.pi_col1 = table2.pi_col2. Не уверен, как использование выражения +1 повлияет на соединение.

Глядя на ваш запрос с высокого уровня, кажется, что вы просто хотите использовать значение предыдущей строки в вычислении текущей строки. Если это так, то вы могли бы вообще отказаться от рекурсивного CTE и просто использовать оконную функцию LAG():

WITH smooth AS (
  SELECT CAST(0.741870935 AS NUMERIC (20,5)) AS alpha
)
SELECT 
  ROW_NUMBER() OVER (ORDER BY customer_name, closed_date) as rn, -- row number
  customer, 
  closed_date, 
  metric,
  CAST(
    COALESCE(
      (smooth.alpha * metric + (1-smooth.alpha)) * -- current row's value
      LAG((smooth.alpha * metric + (1-smooth.alpha))) OVER(
        ORDER BY customer_name, closed_date) -- previous row's value
      , metric -- handle first row (no previous "EWMA" value)
    )
  AS NUMERIC(20,5)) AS EWMA
FROM my_table;
...