窗口函数和查询优化器
Windowed Functions and Query Optimizer
我有一个具有以下结构的 table。
|anId| aDate|aNumber|
-------------------------
| 1|2018-01-20| 100|
| 1|2019-01-01| -100|
| 1|2019-02-01| 10|
| 2|2019-01-02| 40|
我有一个关于 return 的查询,在特定日期,每个 .
之前(含)aNumber
的总和是否为 > 0
select
anId,
aDate,
1 as aStatus
from (
select
anId,
aDate,
sum(aNumber) OVER (
PARTITION BY anId
ORDER BY aDate
ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
) as aSum
from
myTable
)
where
aSum > 0
;
所以这个查询会 return
|anId| aDate|aStatus|
-------------------------
| 1|2018-01-20| 1|
| 2|2019-01-02| 1|
| 1|2019-02-01| 1|
现在我已将查询转换为视图 myView
。我想查询此视图的日期范围。我可能会查询 table daily/monthly/yearly 任何内容,但我希望能够从一个日期范围导出查询结果,然后 export/append 导出下一个日期范围的结果。
select
anId,
aDate,
aStatus
from
myView
where
aDate between (2018-01-01) and (2018-12-31)
;
会return
|anId| aDate|aStatus|
-------------------------
| 1|2018-01-20| 1|
还有下一年
select
anId,
aDate,
aStatus
from
myView
where
aDate between (2019-01-01) and (2019-12-31)
;
应该return
|anId| aDate|aStatus|
-------------------------
| 2|2019-01-02| 1|
| 1|2019-02-01| 1|
允许我将结果拼接在一起以获得原始的、未过滤的查看记录。
好的,既然舞台已经设置好了,我对这种方法的担忧是,当我从视图中过滤日期时,它会影响窗口函数。
当我过滤 2019 年时,加窗后的总和是否仍会包含 2018 年的 aNumber
?我的日期范围过滤器是否会在总和之前应用到内部 select?
创建这个问题后,我意识到它应该足够简单来测试它。
CREATE TABLE [dbo].[myTable](
[anId] [char](36) NOT NULL,
[aDate] [datetime2](7) NULL,
[aNumber] [int] NULL
) ON [PRIMARY]
GO
insert into myTable(anId,aDate,aNumber) values ('1','2018-01-20',100);
insert into myTable(anId,aDate,aNumber) values ('1','2019-01-01',-100);
insert into myTable(anId,aDate,aNumber) values ('1','2019-02-01',10);
insert into myTable(anId,aDate,aNumber) values ('2','2019-01-20',40);
使用子select而不是创建实际视图
select
*
from (
select
anId,
aDate,
1 as aStatus
from (
select
anId,
aDate,
sum(aNumber) OVER (
PARTITION BY anId
ORDER BY aDate
ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
) as aSum
from
myTable
) a
where
a.aSum > 0
) b
where
b.aDate < '2019-01-01'
;
Returns:
|anId| aDate|aStatus|
-------------------------
| 1|2018-01-20| 1|
和
select
*
from (
select
anId,
aDate,
1 as aStatus
from (
select
anId,
aDate,
sum(aNumber) OVER (
PARTITION BY anId
ORDER BY aDate
ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
) as aSum
from
myTable
) a
where
a.aSum > 0
) b
where
b.aDate >= '2019-01-01'
;
Returns:
|anId| aDate|aStatus|
-------------------------
| 2|2019-01-02| 1|
| 1|2019-02-01| 1|
这确认日期过滤器不会影响总和。然而,这让我有些担心子查询不是最优的,因为它可能 运行 跨越比必要更多的数据求和。 IE。当我要2018年的数据时,它是否还在计算2019年数据的总和?
我有一个具有以下结构的 table。
|anId| aDate|aNumber|
-------------------------
| 1|2018-01-20| 100|
| 1|2019-01-01| -100|
| 1|2019-02-01| 10|
| 2|2019-01-02| 40|
我有一个关于 return 的查询,在特定日期,每个 .
之前(含)aNumber
的总和是否为 > 0
select
anId,
aDate,
1 as aStatus
from (
select
anId,
aDate,
sum(aNumber) OVER (
PARTITION BY anId
ORDER BY aDate
ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
) as aSum
from
myTable
)
where
aSum > 0
;
所以这个查询会 return
|anId| aDate|aStatus|
-------------------------
| 1|2018-01-20| 1|
| 2|2019-01-02| 1|
| 1|2019-02-01| 1|
现在我已将查询转换为视图 myView
。我想查询此视图的日期范围。我可能会查询 table daily/monthly/yearly 任何内容,但我希望能够从一个日期范围导出查询结果,然后 export/append 导出下一个日期范围的结果。
select
anId,
aDate,
aStatus
from
myView
where
aDate between (2018-01-01) and (2018-12-31)
;
会return
|anId| aDate|aStatus|
-------------------------
| 1|2018-01-20| 1|
还有下一年
select
anId,
aDate,
aStatus
from
myView
where
aDate between (2019-01-01) and (2019-12-31)
;
应该return
|anId| aDate|aStatus|
-------------------------
| 2|2019-01-02| 1|
| 1|2019-02-01| 1|
允许我将结果拼接在一起以获得原始的、未过滤的查看记录。
好的,既然舞台已经设置好了,我对这种方法的担忧是,当我从视图中过滤日期时,它会影响窗口函数。
当我过滤 2019 年时,加窗后的总和是否仍会包含 2018 年的 aNumber
?我的日期范围过滤器是否会在总和之前应用到内部 select?
创建这个问题后,我意识到它应该足够简单来测试它。
CREATE TABLE [dbo].[myTable](
[anId] [char](36) NOT NULL,
[aDate] [datetime2](7) NULL,
[aNumber] [int] NULL
) ON [PRIMARY]
GO
insert into myTable(anId,aDate,aNumber) values ('1','2018-01-20',100);
insert into myTable(anId,aDate,aNumber) values ('1','2019-01-01',-100);
insert into myTable(anId,aDate,aNumber) values ('1','2019-02-01',10);
insert into myTable(anId,aDate,aNumber) values ('2','2019-01-20',40);
使用子select而不是创建实际视图
select
*
from (
select
anId,
aDate,
1 as aStatus
from (
select
anId,
aDate,
sum(aNumber) OVER (
PARTITION BY anId
ORDER BY aDate
ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
) as aSum
from
myTable
) a
where
a.aSum > 0
) b
where
b.aDate < '2019-01-01'
;
Returns:
|anId| aDate|aStatus|
-------------------------
| 1|2018-01-20| 1|
和
select
*
from (
select
anId,
aDate,
1 as aStatus
from (
select
anId,
aDate,
sum(aNumber) OVER (
PARTITION BY anId
ORDER BY aDate
ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
) as aSum
from
myTable
) a
where
a.aSum > 0
) b
where
b.aDate >= '2019-01-01'
;
Returns:
|anId| aDate|aStatus|
-------------------------
| 2|2019-01-02| 1|
| 1|2019-02-01| 1|
这确认日期过滤器不会影响总和。然而,这让我有些担心子查询不是最优的,因为它可能 运行 跨越比必要更多的数据求和。 IE。当我要2018年的数据时,它是否还在计算2019年数据的总和?