Оконные функции и оптимизатор запросов

У меня есть таблица со следующей структурой.

|anId|     aDate|aNumber|
-------------------------
|   1|2018-01-20|    100|
|   1|2019-01-01|   -100|
|   1|2019-02-01|     10|
|   2|2019-01-02|     40|

У меня есть запрос, чтобы вернуть, на определенную дату, независимо от того, был ли ранее (включительно) 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
;

Так что этот запрос вернет

|anId|     aDate|aStatus|
-------------------------
|   1|2018-01-20|      1|
|   2|2019-01-02|      1|
|   1|2019-02-01|      1|

Теперь я превратил запрос в представление myView, Я хотел бы запросить это представление для диапазонов дат. Я могу запросить таблицу ежедневно / ежемесячно / ежегодно, но я хочу иметь возможность экспортировать результаты запроса из одного диапазона дат, а затем экспортировать / добавить результаты для следующего диапазона дат.

select
  anId,
  aDate,
  aStatus
from
  myView
where
  aDate between (2018-01-01) and (2018-12-31)
;

Вернется

|anId|     aDate|aStatus|
-------------------------
|   1|2018-01-20|      1|

И в следующем году

select
  anId,
  aDate,
  aStatus
from
  myView
where
  aDate between (2019-01-01) and (2019-12-31)
;

Должен вернуться

|anId|     aDate|aStatus|
-------------------------
|   2|2019-01-02|      1|
|   1|2019-02-01|      1|

Позволяет мне склеивать результаты, чтобы получить исходные, нефильтрованные записи.


Хорошо, теперь, когда этап установлен, моя проблема с этим подходом заключается в том, что когда я отфильтрую дату из представления, это повлияет на оконную функцию.

Когда я отфильтрую 2019, будет ли оконная сумма по-прежнему включать 2018 aNumbers? Будет ли мой фильтр диапазона дат применен во внутреннем выборе до суммы?

1 ответ

Создав этот вопрос, я понял, что это должно быть достаточно просто, чтобы проверить его.

CREATE TABLE [dbo].[jnix_temp](
    [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
    *
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'
;

Возвращает:

|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'
;

Возвращает:

|anId|     aDate|aStatus|
-------------------------
|   2|2019-01-02|      1|
|   1|2019-02-01|      1|

Это подтверждает, что фильтр даты не влияет на суммы. Однако это вызывает у меня некоторую обеспокоенность тем, что подзапрос является неоптимальным, поскольку он может выполнять суммирование по значительно большему количеству данных, чем необходимо. то есть. когда мне нужны данные за 2018 год, все еще рассчитываются суммы для данных за 2019 год?

Другие вопросы по тегам