DB2 SQL: самый быстрый способ получить запаздывающее значение для многих столбцов - PullRequest
0 голосов
/ 30 мая 2018

Есть много способов получить запаздывающее значение определенного столбца в SQL, например:

WITH CTE AS (
  SELECT
    rownum = ROW_NUMBER() OVER (ORDER BY columns_to_order_by),
    value
  FROM table
)
SELECT
  curr.value - prev.value
FROM CTE cur
INNER JOIN CTE prev on prev.rownum = cur.rownum - 1

или:

select variable_of_interest 
               ,lag(variable_of_interest ,1) 
                    over(partition by
                    some_group order by variable_1,...,variable_n) 
                    as lag_variable_of_interest
from DATA

Я использую вторую версию, но мойкод работает очень медленно, когда «отстает» от многих переменных, так что мой код становится:

select        variable_of_interest_1
              ,variable_of_interest_2
              ,variable_of_interest_3
                   ,lag(variable_of_interest_1 ,1) 
                        over(partition by
                        some_group order by variable_1,...,variable_n) 
                        as lag_variable_of_interest_1
                    ,lag(variable_of_interest_2 ,1) 
                        over(partition by
                        some_group order by variable_1,...,variable_n) 
                        as lag_variable_of_interest_2
                   ,lag(variable_of_interest_3 ,1) 
                        over(partition by
                        some_group order by variable_1,...,variable_n) 
                        as lag_variable_of_interest_3
    from DATA

Интересно, так ли это, потому что каждая функция запаздывания должна иметь свой собственный раздел и упорядочивать весь набор данных, даже еслииспользуете тот же раздел и порядок?

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

Db2 отсортирует данные только один раз, если все функции OLAP используют одинаковые PARTITION BY и ORDER BY.Вы можете подтвердить это, посмотрев план объяснения.

create table data(v1 int, v2 int, v3 int, g1 int, g2 int, o1 int, o2 int) organize by row
;
explain plan for
select  g1
,       g2
,       o1
,       o2
,       v1
,       v2
,       v3
,       lag(v1) over(partition by g1, g2 order by o1, o2 ) as lag_v1
,       lag(v2) over(partition by g1, g2 order by o1, o2 ) as lag_v2
,       lag(v3) over(partition by g1, g2 order by o1, o2 ) as lag_v3
from
    data
;

даст следующий план (используя db2exfmt -1 -d $DATABASE).Вы можете видеть, что есть только один SORT оператор

Access Plan:
-----------

    Total Cost:             14.839
    Query Degree:           4



      Rows 
     RETURN
     (   1)
      Cost 
       I/O 
       |
      1000 
     LMTQ  
     (   2)
     14.839 
        2 
       |
      1000 
     TBSCAN
     (   3)
     14.5555 
        2 
       |
      1000 
     SORT  
     (   4)
     14.5554 
        2 
       |
      1000 
     TBSCAN
     (   5)
     14.2588 
        2 
       |
      1000 
 TABLE: PAUL    
      DATA
       Q1

Кстати, если вы отправите вопрос с реальным запросом SQL (вместе с некоторым DDL и некоторым представлением об объемах данных), мы могли быпредложить вещи, которые могут улучшить производительность получения отстающих значений.Трудно советовать подробно, не видя лучшего примера

0 голосов
/ 30 мая 2018

Я не уверен на 100% в том, как DB2 оптимизирует такие запросы.Если он выполняет каждую задержку независимо, тогда определенно есть место для улучшения оптимизатора.

Один из способов, который вы можете использовать, - lag() с join на первичном ключе :

select t.*, tprev.*
from (select t.*, lag(id) over ( . . . ) as prev_id
      from t
     ) t left join
     t tprev
     on t.id = tprev.prev_id ;

Из того, что вы описываете, это может быть самый эффективный способ сделать то, что вы хотите.

Это должно быть более эффективно, чем row_number(), потому что объединение может использовать индекс.

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