Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 Контент вільний від AI. Цей пост на 100% написаний людиною, як і все на моєму блозі. Насолоджуйтесь!

16.01.2023

Віконні функції PostgreSQL, або ж COUNT+LIMIT одним запитом

Сьогодні повернувся до роботи, а робота в мене зараз — це боротьба з Redshift. Тому маленька, але дуже цінна порада. Вона стосується тієї ситуації, коли потрібно для деякого запиту одночасно й обмежити кількість рядків, і дізнатись, скільки їх є взагалі. Тобто класичної пейджинації.

Я все життя просто робив окремий запит. Тільки що перевірив, і виходить, що не тільки я — найпопулярніша бібліотека для пейджинації у Rails - Kaminari - теж робить окремий запит. У нормальних умовах це і не погано, бо ніхто і не помітить уповільнення. Але якщо у вас пейджинується складний запит, виконання якого займає 3 секунди, то робити його другий раз вже не хочеться. Проте моніторинг, який я передбачливо налаштував перед відпусткою, саме таке і показав — що виклик API робить 2 майже однакових запити — один на COUNT, один на LIMIT - та замість трьох секунд триває шість.

Мені не хотілось вірити, що це найкраще, на що здатний Redshift, тож озброєний цією вірою, пішов шукати розвʼязок. Та знайшов, у так званих віконних функціях. Якщо просто, то віконна функція оперує не тільки поточним рядком, але й іншими рядками. Головне, вона виконується до операції LIMIT. В моєму випадку потрібна найпростіша функція: COUNT(*) OVER (). Вона значить: підрахувати рядки, використовуючи вікно без жодних обмежень, тобто всі рядки. Але з віконними функціями можна робити й цікавіші речі — наприклад, повертати в кожному рядку статистику по рядках зі схожими атрибутами. Віконні функції зустрічаються в секції SELECT, тобто результат буде повернений як стовпчик:

SELECT *, COUNT(*) OVER () AS total_count FROM big_view WHERE ...

В цьому випадку значення для всіх рядків буде однакове, тож залишається взяти total_count з найпершого рядка, і задача розвʼязана.