[personal profile] tsarev
Уже не первый раз просят дать какую-нибудь книжку по window functions.
Ирония состоит в том, что я такой книжки не знаю, но window functions реализовал руками когда писал СУБД.
Попробую сейчас написать небольшую статью, прочитав которую, скорей всего, вы будете "понимать" window functions без мучительного вычитывания стандарта и кучи текстов разной степени понятности.
Поехали


Любой window function состоит из
1) агрегационных функций
2) over (определения окна)

Агрегационные функции можно классицировать на
1а) "классические агрегаты" (sum, count)
1б) "аналитические агрегаты" (row_number, rank, dense_rank)

Определение окна состоит из
2а) partition by
2b) order by
2c) sliding window (опциональный) (rows between undounded preceding and current row как пример)

Как window functions влияет на остальной запрос:
- на выходе из window functions всегда ровно столько строчек, сколько на входе == "window functions проксирует вход"
- все конструкции из определения окна влияют ТОЛЬКО на вычисления агрегаттов
- НО! если у вас в запросе явно не указан order by (ЗА ПРЕДЕЛАМИ OVER!), то в полном соответствии с SQL стандартом, база может переупорядочить строчки так, чтобы window functions считались быстро, таким образом, порядок строчек в запросе с window functions МОЖЕТ отличаться от порядка строчек без него

Теперь рассмотрим вычисления агреггатов
Сначала применяется partition by, который группирует строчки по ключу partition by. Если в запросе нету внешнего order by (ЗА ПРЕДЕЛАМИ OVER!), то, скорей всего, строки в результате выполнения запроса будет сгруппированы (НО ЭТО НЕ ГАРАНТИРУЕТСЯ! и на это нельзя полагаться)

Оба типа агреггатов (классические и аналитические) считаются по отдельным parition (с одинаковым ключем)
Если partition by опущен - по всей выборке

Ну и последнее правило.
Всe агрегаты вычислются в рамках одного partition
- в соответствии с порядком order by ВНУТРИ over
- на подмножестве строк, ограниченном sliding winding.

У sliding window есть такая важная штука, как current row.
При выдаче строчки наружу из window function, current row - это текущая строчка из входа (смотрите выше правило "window functions проксирует вход")

sliding window бывают двух типов: rows и range

"rows" задает относительное смещение от current row
rows between unbounded preceding and current row - от начала текущего partition и до текущей строки
rows between 3 preceding and 3 following - минус 3 строки назад и плюс 3 строки вперед от текущей строки

range работает почти также, только он не просто "считает" строки, а он их "группирует" по ключу order by.
Если у вас идут повторяющиеся строки, то range - это такая дополнительная их группировка, и отсчет идет по группам строк, у которых значения в колонках из order by одинаковые

Собственно, все, через этот небольшой ряд правил и модель выполнения вы сможете разобраться в любом запросе с window functions и написать нужный вам

Правила разбора (сжато)
- на выходе будет столько же строк, сколько в запросе без window functions
- разберитесь c order by - он управляет порядком строк в sliding window (и НИЧЕГО не говорит про порядок в результате)
- разберитесь с sliding window (в случае range помните про order by)

Есть один красивый пример, который иллюстриует как внутренний order by не влияет на результат выполнения запроса так, как внешний order by

Если у вас есть запрос вида
OVER (ORDER BY c ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
скорей всего, оптимизатор развернет этот запрос в такой:
OVER (ORDER BY c DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

Т.е. СУБД "перевернет" окно, потому что preceding...current row считать проще, чем current row...following.
Во всяком случае, SyBase именно так делает

Это абсолютно легальная операция - поменять порядок order by и перевернуть окно
Но на выходе из запроса у вас порядок строк (при отсутствии внешнего order by) будет "перевернутым"

May 2017

S M T W T F S
 1 23456
78910111213
14151617181920
21222324252627
28293031   

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 28th, 2017 12:41 pm
Powered by Dreamwidth Studios