DB2 SQL:获取多列滞后值的最快方法
DB2 SQL: fastest way to get lagged value of many columns
获取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
我用的是第二个版本,但是当"lagging"很多变量时我的代码运行起来很慢,这样我的代码就变成了:
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
我想知道,这是不是因为每个滞后函数都必须按自己的分区对整个数据集进行排序,即使它们使用相同的分区和顺序?
我不是 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()
更有效,因为连接可以使用索引。
如果所有 OLAP 函数都使用相同的 PARTITION BY
和 ORDER BY
,Db2 只会对数据进行一次排序。您可以通过查看解释计划来确认这一点。
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
operator
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
顺便说一句,如果您 post 有一个真正的 SQL 查询问题(连同一些 DDL 和对数据量的一些想法),我们可能会提出可以提高性能的建议获得滞后值。没有看到更好的例子很难详细建议
获取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
我用的是第二个版本,但是当"lagging"很多变量时我的代码运行起来很慢,这样我的代码就变成了:
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
我想知道,这是不是因为每个滞后函数都必须按自己的分区对整个数据集进行排序,即使它们使用相同的分区和顺序?
我不是 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()
更有效,因为连接可以使用索引。
如果所有 OLAP 函数都使用相同的 PARTITION BY
和 ORDER BY
,Db2 只会对数据进行一次排序。您可以通过查看解释计划来确认这一点。
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
operator
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
顺便说一句,如果您 post 有一个真正的 SQL 查询问题(连同一些 DDL 和对数据量的一些想法),我们可能会提出可以提高性能的建议获得滞后值。没有看到更好的例子很难详细建议