В чем разница между обычным VIEW и MATERIALIZED VIEW в базах данных
Что проверяют
Понимаете ли вы, где на самом деле лежат данные и чем платят за скорость чтения. Для Java-разработчика следом почти всегда идут вопросы: как обновлять материализованное представление и как замапить представление в JPA.
Как отвечать
- VIEW: сохранённый запрос без собственных данных. При обращении планировщик подставляет его текст в ваш запрос и оптимизирует целиком, поэтому данные всегда актуальны, а скорость такая же, как у исходного запроса. Простые представления в PostgreSQL обновляемые:
INSERTиUPDATEчерез них проходят в базовую таблицу; - MATERIALIZED VIEW: результат запроса, сохранённый на диск как таблица. Читается быстро, на него можно повесить индексы, но данные замораживаются на момент последнего обновления.
Главное различие в обновлении. В PostgreSQL это только явная команда REFRESH MATERIALIZED VIEW, которая пересчитывает всё целиком и на время пересчёта блокирует чтение. Вариант CONCURRENTLY чтение не блокирует, но требует уникального индекса на представлении. Встроенного расписания нет: обновление запускают через pg_cron или из приложения, например методом с @Scheduled в Spring. В Oracle есть инкрементальное обновление FAST по журналам изменений и режим ON COMMIT. В MySQL материализованных представлений нет вовсе, их эмулируют таблицей и джобой.
Со стороны Java представление мапят как сущность только для чтения: @Entity с @Immutable из Hibernate, а для материализованного добавляют метод репозитория с нативным запросом на обновление.
Когда что брать: обычное представление для инкапсуляции сложного запроса и ограничения доступа к колонкам, материализованное для тяжёлых агрегатов в отчётах и дашбордах, где задержка в минуты допустима.
Где спотыкаются
Считают, что обычное представление само по себе медленное. Замедляет не представление, а запрос внутри него: EXPLAIN обычно покажет тот же план, что и без обёртки.
Обещают, что материализованное представление обновится само при изменении таблиц. В PostgreSQL этого не будет, пока его явно не обновят.
Забывают про стоимость REFRESH на больших данных: полный пересчёт раз в минуту может нагрузить базу сильнее, чем исходные запросы.