
История, которая началась с неловкого момента на собеседовании, вылилась в детальное практическое исследование производительности VIEW в двух популярных СУБД. Автор блога на «Хабре» под ником «Меня подняли на смех за ответ про VIEW» рассказал, как его честный ответ о редком использовании представлений в реальных проектах был встречен смехом и фразой «Ничего ты не понимаешь во VIEW». Спустя время он решил проверить, изменилась ли ситуация с выходом новых версий MySQL 8.4.11 и PostgreSQL 17.11.
Результаты тестов оказались неочевидными и полезными для разработчиков, которые проходят собеседования или проектируют схемы баз данных в коммерческих проектах. Основной вывод: проблема агрегирующих VIEW не в том, что они «считают всё до фильтра», а в том, что они «молча» скрывают несоответствие типов колонок и индексов.
Ключевые факты
| Параметр | Значение |
|---|---|
| Версии СУБД | MySQL 8.4.11, PostgreSQL 17.11 |
| Объём тестовых данных | 1 млн заказов, 2 млн позиций, 780 тыс. платежей, 100 продавцов |
| Основной сценарий | Агрегирующая VIEW с группировкой по дате и продавцу |
| Максимальное замедление | PostgreSQL: 24.5 мс через VIEW против 1.85 мс прямым запросом (в 13 раз) |
| Неожиданный результат | Каскад из трёх VIEW в MySQL оказался быстрее прямого запроса (1436 мс против 2432 мс) |
Как проходил тест
Автор развернул обе СУБД в Docker Compose, загрузил идентичные детерминированные данные по схеме интернет-магазина: заказы, позиции, платежи, справочник продавцов. Данные — побайтово одинаковые в обеих базах. Набор представлений зеркальный: простая обёртка, дневной агрегат, каскад из трёх уровней, а также ловушка с ORDER BY внутри.
Измерялось серверное время выполнения. В MySQL использовался корневой actual time из EXPLAIN ANALYZE, в PostgreSQL — Execution Time. Два прогрева, семь замеров, бралась медиана.
Что показал бенчмарк
Простая обёртка над таблицей без агрегации показала практически одинаковое время в обеих СУБД — 1,5–2 миллисекунды. Оптимизаторы в обоих случаях «сливают» VIEW с запросом так, что разницы с прямым обращением к таблице нет.
Проблема возникла с агрегирующей VIEW. Запрос к ней в PostgreSQL выполнялся 24.5 мс, тогда как тот же результат прямым запросом — 1.85 мс. Разница в 13 раз. Причина не в том, что агрегация считается до фильтра, как часто пишут в статьях. Планы выполнения показали: оба предиката (merchant_id и day) проталкиваются под GROUP BY, и агрегируются только отфильтрованные строки.
Проблема в другом: через VIEW условие приходит в виде CAST(created_at AS DATE) >= ‘2026-06-01’ — это выражение, а не колонка. Индекс (merchant_id, created_at) не может использоваться для диапазонного поиска по такой записи. В результате PostgreSQL вытаскивает все 10 тысяч заказов продавца за 21 месяц, а затем отбрасывает 9531 строку фильтром. Это вызывает 8971 обращение к буферам против 440 у прямого запроса.
MySQL на том же месте показал 4.85 мс против 2.16 мс — всего в два раза медленнее. Спасает MySQL то, что он умеет вычислять CAST прямо в индексе (index condition pushdown), не поднимая строки-кандидаты из таблицы.
Неожиданный поворот: каскад из трёх VIEW
Автор протестировал трёхуровневый каскад: дневной агрегат, сумма поверх него, join со справочником наверху. Ожидалось, что чем глубже стопка, тем хуже. PostgreSQL подтвердил это: 832 мс против 243 мс у однопроходного запроса.
MySQL же показал обратное: каскад из трёх VIEW (1436 мс) оказался почти вдвое быстрее прямого запроса (2432 мс). Причина — порядок выполнения join. Прямой запрос соединяет таблицу заказов со справочником до группировки, вызывая 750 тысяч точечных обращений по первичному ключу. В каскаде join уходит на самый верх, где после двух агрегаций обрабатывается всего 75 строк.
Для PostgreSQL каскад оказался хуже из-за потери параллелизма и нехватки work_mem (4 МБ по умолчанию). Промежуточные 48 тысяч групп не влезли в память, и СУБД сбросила 30 МБ на диск за одно выполнение. За серию из девяти прогонов temp_bytes выросли на 278 МБ.
Что это значит для IT-специалистов
Для разработчиков, которые проходят собеседования или проектируют схемы баз данных, этот бенчмарк даёт практические уроки:
- Агрегирующие VIEW не «считают всё раньше времени» — оптимизаторы умеют проталкивать фильтры. Проблема в том, что VIEW «молча» меняет тип колонки, и индекс перестаёт работать.
- При виде CREATE VIEW … GROUP BY в pull request стоит уточнять, какие колонки выставлены наружу и есть ли под ними индексы. В восьми случаях из десяти этого хватает.
- Каскад VIEW может быть быстрее прямого запроса в MySQL, если join уходит на самый верх воронки. В PostgreSQL тот же каскад теряет параллелизм и может привести к сбросу на диск.
- Для собеседований: знание планов выполнения и понимание, как VIEW влияет на типы колонок, ценнее, чем общие утверждения о «нишевости» представлений.
Источник: Хабр — «Меня подняли на смех за ответ про VIEW. Я поднял MySQL 8.4 и PostgreSQL 17 и померил» (https://habr.com/ru/articles/1074534/)