Партиции в оконных функциях

В прошлой статье мы кратко уже упоминали, что такое партиции и как их использовать в оконных функциях, пришло время разобраться в них поподробнее 🤓.

Понятие партиции

Партиции — подмножества строк, выделенные для оконной функции на основе одного или нескольких столбцов в таблице.

Они служат для сегментации данных, позволяя выполнить более детальный анализ и расчёты вроде агрегации или ранжирования внутри каждой такой группы.

Применяя партиционирование, например, по типу жилья в таблице с данными о цене жилья, мы можем рассчитать в отдельной колонке, скажем, среднюю цену для каждого типа жилья.

Схема разбиения на партиции

Применение партиций в SQL

Для того, чтобы использовать партицию вместе с оконной функцией необходимо придерживаться следующего синтаксиса:

MySQL
SELECT <оконная_функция>(<поле_таблицы>)
OVER (
    PARTITION BY <столбцы_для_разделения>
)

Пример использования

А теперь давайте на простом примере рассмотрим использование партиции вместе с оконной функцией.

Для этого рассмотрим таблицу Rooms, а именно поля home_type и price:

MySQL
SELECT home_type, price FROM Rooms;
home_typeprice
Private room149
Entire home/apt225
Private room150
Entire home/apt89
Entire home/apt80
Entire home/apt200
Private room60
Private room79
Private room79
Entire home/apt150
Entire home/apt135
Private room85
Private room89
Private room85
Entire home/apt120
Entire home/apt140
Entire home/apt215
Private room140
Entire home/apt99
Entire home/apt190
Entire home/apt299
Private room130
Private room80
Private room110
Entire home/apt120
Private room60
Private room80
Entire home/apt150
Private room44
Entire home/apt180
Private room50
Private room52
Private room55
Private room50
Private room70
Private room89
Private room35
Entire home/apt85
Private room150
Shared room40
Private room68
Entire home/apt120
Private room120
Private room135
Entire home/apt150
Entire home/apt150
Private room130
Entire home/apt110
Entire home/apt115
Private room80

Мы можем увидеть, что все жильё для аренды разделено на 3 категории: «Private room», «Entire home/apt» и «Shared room».

Каждая категория жилья имеет свои ценовые рамки. Чтобы узнать среднюю стоимость в конкретной категории и сравнить её с текущей, как раз можно использовать оконные функции.

Для этого добавим к нашей результирующей таблице ещё одно поле avg_price, которое будет высчитывать среднюю цену по категориям. Это будет выглядеть следующим образом:

MySQL
SELECT
    home_type, price,
    AVG(price) OVER (PARTITION BY home_type) AS avg_price
FROM Rooms
home_typepriceavg_price
Entire home/apt225148.6667
Entire home/apt180148.6667
Entire home/apt150148.6667
Entire home/apt85148.6667
Entire home/apt120148.6667
Entire home/apt120148.6667
Entire home/apt299148.6667
Entire home/apt190148.6667
Entire home/apt99148.6667
Entire home/apt215148.6667
Entire home/apt140148.6667
Entire home/apt120148.6667
Entire home/apt150148.6667
Entire home/apt135148.6667
Entire home/apt150148.6667
Entire home/apt110148.6667
Entire home/apt115148.6667
Entire home/apt200148.6667
Entire home/apt150148.6667
Entire home/apt80148.6667
Entire home/apt89148.6667
Private room6889.4286
Private room5089.4286
Private room7089.4286
Private room8089.4286
Private room8989.4286
Private room14989.4286
Private room3589.4286
Private room15089.4286
Private room13089.4286
Private room12089.4286
Private room13589.4286
Private room13089.4286
Private room15089.4286
Private room6089.4286
Private room7989.4286
Private room7989.4286
Private room8589.4286
Private room8989.4286
Private room8589.4286
Private room14089.4286
Private room5589.4286
Private room8089.4286
Private room11089.4286
Private room6089.4286
Private room8089.4286
Private room4489.4286
Private room5089.4286
Private room5289.4286
Shared room4040

Что именно происходит в добавленной строке?

  • PARTITION BY home_type делит все записи на разные партиции на основе уникальных значений столбца home_type
  • затем, для каждой записи, AVG(price) вычисляет среднюю цену (price) в рамках её партиции (home_type)

Результатом выполнения этой части запроса будет столбец avg_price, в котором для каждой записи будет указано среднее значение цены для её категории жилья (home_type).

Партиции по нескольким колонками

Партиционирование также может быть выполнено по нескольким колонкам. Это позволяет создавать более сложные и точные сегменты для анализа.

Например, для нашей таблицы Rooms мы можем создать партиции на основании 2 колонок: категория жилья home_type и наличие телевизора в жилье has_tv.

Пример запроса с партиционированием по двум столбцам:

MySQL
SELECT
    home_type, has_tv, price,
    AVG(price) OVER (PARTITION BY home_type, has_tv) AS avg_price
    FROM Rooms
home_typehas_tvpriceavg_price
Entire home/apt0225170
Entire home/apt0180170
Entire home/apt080170
Entire home/apt0200170
Entire home/apt0150170
Entire home/apt0150170
Entire home/apt0190170
Entire home/apt0215170
Entire home/apt0140170
Entire home/apt199132.6667
Entire home/apt185132.6667
Entire home/apt1150132.6667
Entire home/apt1120132.6667
Entire home/apt1120132.6667
Entire home/apt1299132.6667
Entire home/apt1120132.6667
Entire home/apt1135132.6667
Entire home/apt1150132.6667
Entire home/apt1110132.6667
Entire home/apt189132.6667
Entire home/apt1115132.6667
Private room08578.5455
Private room03578.5455
Private room015078.5455
Private room05578.5455
Private room05278.5455
Private room05078.5455
Private room06878.5455
Private room06078.5455
Private room013578.5455
Private room08578.5455
Private room08978.5455
Private room112096.4706
Private room18096.4706
Private room114996.4706
Private room113096.4706
Private room18996.4706
Private room17096.4706
Private room15096.4706
Private room14496.4706
Private room18096.4706
Private room16096.4706
Private room111096.4706
Private room18096.4706
Private room113096.4706
Private room114096.4706
Private room17996.4706
Private room17996.4706
Private room115096.4706
Shared room14040

Здесь PARTITION BY home_type, has_tv создаёт уникальные партиции для каждой комбинации home_type и has_tv, позволяя вычислить среднюю цену жилья для текущей категории жилья с наличием или без наличия телевизора.

Партиции по 2 колонками