Trino: Difference between "ROWS BETWEEN" and "RANGE BETWEEN" in (Presto) window function "OVER" clause
Ты пишешь запрос с оконной функцией в Presto, гуглишь синтаксис и видишь два варианта: `ROWS BETWEEN` и `RANGE BETWEEN`. Пытаешься понять разницу, а документаци
Ты пишешь запрос с оконной функцией в Presto, гуглишь синтаксис и видишь два варианта: ROWS BETWEEN и RANGE BETWEEN. Пытаешься понять разницу, а документация молчит. Или намекает, но непонятно.
Особенно если работаешь с Amazon Athena, которая застряла на старых версиях PrestoSQL. Именно там эта разница проявляется во всей красе.
ROWS и RANGE — это не синонимы
Все просто. ROWS работает со строками, RANGE — со значениями.
Когда пишешь ORDER BY day ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING, движок берет буквально одну предыдущую и одну следующую строку из результирующего набора. Не важно, какие значения в day. Всегда будет три строки (если они есть).
А вот ORDER BY day RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING смотрит на значение в колонке day. Он включит в окно все строки, где значение day попадает в диапазон [текущее_значение - 1, текущее_значение + 1]. Если в этот диапазон попадает десять строк с одинаковыми датами — в окне будет десять строк.
Почему в Presto всё странно
В старых версиях Presto (например, 0.172, на котором работает Athena Engine 1) RANGE реализован частично. По факту, с ним можно использовать только UNBOUNDED и CURRENT ROW.
-- Так работает в старом Presto / Athena v1
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-- А так, скорее всего, вызовет ошибку
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING
Поэтому создается ложное впечатление, что ROWS «мощнее» — у него больше опций для указания границ окна. Документация молчала, потому что функционал был сырой.
В Trino (который стал наследником PrestoSQL) эту проблему исправили, начиная с версии 346. Там RANGE и новый тип GROUPS работают полноценно.
Когда результаты будут разными
Попробуй этот мысленный эксперимент на данных, где есть дубликаты по колонке из ORDER BY.
-- Данные
day | value
-----------
1 | 100
1 | 200
2 | 50
3 | 300
-- ROWS BETWEEN 1 PRECEDING AND CURRENT ROW для 3-й строки (day=2)
-- В окно попадут строки: (day=1, value=200) и (day=2, value=50)
-- RANGE BETWEEN 1 PRECEDING AND CURRENT ROW для 3-й строки (day=2)
-- Диапазон значений day: [1, 2]
-- В окно попадут ВСЕ строки, где day=1 или day=2. Это три строки.
Разница налицо. С RANGE при наличии одинаковых значений в порядке сортировки окно «раздувается».
Что делать в Athena или старом Presto
Правило простое. Если нужен контроль именно над количеством строк — используй ROWS. Если логика должна зависеть от значений в колонке сортировки — в старых версиях тебе не повезло, RANGE не поможет. Придется выкручиваться подзапросами или самописной логикой агрегации.
Всегда проверяй, какая версия движка у тебя под капотом. Athena Engine 2 (Presto 0.217) уже лучше, но для полного счастья нужен современный Trino.
Лучший способ понять разницу — создать тестовый датасет с дубликатами и выполнить оба запроса. Так ты увидишь расхождения не на словах, а на реальных числах.