Материализованные представления в Hive

Материализованное представление (Materialized View, MV) — это объект, хранящий результаты выполнения определенного запроса, которые в будущем используются вместо чтения данных из базы. Обычно MV используются для повышения производительности путем "кеширования" результатов больших запросов со сложными агрегациями, объединениями, фильтрами и так далее.

В данном разделе описаны основные операции с MV, а также примеры их использования. Более детальная информация о работе с MV в Hive доступна в документации Apache Hive.

Тестовая база данных

Для демонстрации примеров в данной статье используются Hive-таблицы employees и departments, структура которых описана ниже.

SELECT * FROM employees;
+---------------+-----------------+----------------------+----------------------------+----------------+-------------------+--------------------+
| employees.id  | employees.name  | employees.last_name  |      employees.email       | employees.age  | employees.salary  | employees.dept_id  |
+---------------+-----------------+----------------------+----------------------------+----------------+-------------------+--------------------+
| 1             | Ivan            | Ivanov               | ivan_ivanov123@mail.ru     | 30             | 1000              | 1                  |
| 2             | Sarah           | Connor               | sarah_connor123@yahoo.com  | 35             | 1500              | 2                  |
| 3             | Rick            | Sanchez              | rick_123@mail.ru           | 29             | 1300              | 2                  |
| 4             | John            | Smith                | john_smith123@gmail.com    | 29             | 2000              | 3                  |
+---------------+-----------------+----------------------+----------------------------+----------------+-------------------+--------------------+

SELECT * FROM departments;
+-----------------+-----------------------+-------------------------+------------------------+
| departments.id  | departments.dep_name  | departments.dep_office  | departments.dep_phone  |
+-----------------+-----------------------+-------------------------+------------------------+
| 1               | sales                 | 110                     | 9379992                |
| 2               | it                    | 115                     | 12345678               |
| 3               | support               | 125                     | 880080080              |
+-----------------+-----------------------+-------------------------+------------------------+
SQL для создания тестовых таблиц

 
Для создания и наполнения тестовых таблиц Hive выполните следующий SQL с помощью /bin/beeline.

CREATE DATABASE IF NOT EXISTS mv_demo;
USE mv_demo;

DROP TABLE IF EXISTS employees;
CREATE TABLE employees (id int, name string, last_name string, email string, age int, salary int, dept_id int)
 STORED AS ORC
 TBLPROPERTIES ('transactional'='true');

INSERT INTO employees VALUES
(1, 'Ivan', 'Ivanov', 'ivan_ivanov123@mail.ru', 30, 1000, 1),
(2, 'Sarah', 'Connor', 'sarah_connor123@yahoo.com', 35, 1500, 2),
(3, 'Rick', 'Sanchez', 'rick_123@mail.ru', 29, 1300, 2),
(4, 'John', 'Smith', 'john_smith123@gmail.com', 29, 2000, 3);

DROP TABLE IF EXISTS departments;
CREATE TABLE departments (id int, dep_name string, dep_office int, dep_phone string)
STORED AS ORC
TBLPROPERTIES ('transactional'='true');

INSERT INTO departments VALUES
(1, 'sales', 110, '9379992'),
(2, 'it', 115, '12345678'),
(3, 'support', 125, '880080080');

Синтаксис

Поскольку технически MV — это обычная таблица Hive (хотя и с некоторыми ограничениями), синтаксис для создания нового MV аналогичен синтаксису создания таблиц Hive. Для создания MV используется следующий синтаксис:

CREATE MATERIALIZED VIEW [IF NOT EXISTS] [<db_name>.]<mv_name>
  [DISABLE REWRITE]
  [COMMENT <comment>]
  [PARTITIONED ON (<col_name>, ...)]
  [CLUSTERED ON (<col_name>, ...) | DISTRIBUTED ON (<col_name>, ...) SORTED ON (<col_name>, ...)]
  [
    [ROW FORMAT <row_format>]
    [STORED AS <file_format>] | STORED BY '<storage.handler.class.name>' [WITH SERDEPROPERTIES (...)]
  ]
  [LOCATION <hdfs_path>]
  [TBLPROPERTIES (<property_name>=<property_value>, ...)]
AS
<query>;

Где:

  • <query> — запрос для наполнения MV данными.

  • DISABLE REWRITE — отключает автоматическое переписывание запросов для данного MV.

  • PARTITIONED ON — позволяет дробить MV на партиции по столбцу для лучшей производительности.

  • CLUSTERED ON — используется для разделения MV на примерно равные бакеты, что облегчает обслуживание и увеличивает скорость работы. Каждый бакет хранится в HDFS в виде отдельного файла.

  • ROW FORMAT — определяет форматирование строк, используя либо разделители, либо кастомный SerDe-класс.

  • STORED AS — устанавливает формат хранения данных. По умолчанию используется формат ORC.

  • STORED BY — указывает имя класса-обработчика для сохранения данных MV в ненативном формате.

  • LOCATION — указывает путь в HDFS для сохранения данных MV.

  • TBLPROPERTIES — список пар ключ/значение для настройки параметров MV.

Переписывание запросов

После создания MV оптимизатор Hive автоматически переписывает входящие запросы таким образом, чтобы задействовать MV, если посчитает, что это улучшит производительность. Механизм переписывания запросов включен по умолчанию и может быть отключен при создании MV (предложение DISABLE REWRITE) или с помощью следующей команды:

ALTER MATERIALIZED VIEW <mv_name> DISABLE REWRITE;

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

SET hive.materializedview.rewriting=false;

Если MV устаревает (содержимое MV не обновляется в течение длительного времени), Hive перестает использовать этот MV для переписывания запросов. Время, по истечении которого MV считается устаревшим, можно задать с помощью свойства hive.materializedview.rewriting.time.window"="Nmin" в разделе Custom hive-site.xml настроек ADCM.

ВАЖНО
Функция автоматического переписывания запросов недоступна, если MV был создан из нетранзакционной таблицы. Исходные таблицы Hive должны быть managed и ACID-таблицами.

Обновление материализованного представления

После создания MV любые изменения в исходных таблицах автоматически не отражаются в MV. Процесс обновления MV необходимо запускать вручную с помощью команды:

ALTER MATERIALIZED VIEW <mv_name> REBUILD;

Если новые данные были добавлены в исходные таблицы с помощью INSERT, Hive выполняет инкрементное обновление. Для операций UPDATE и DELETE выполняется полное обновление.

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

Далее показаны основные операции с MV:

  1. Создайте новый MV, используя тестовые таблицы.

    CREATE MATERIALIZED VIEW mv_emp_dp
      AS SELECT e.name, e.last_name, e.email, d.dep_name
      FROM employees e JOIN departments d
      ON (e.dept_id = d.id);
  2. Проверьте, что MV был успешно создан:

    SHOW MATERIALIZED VIEWS;

    Вывод:

    +------------+
    |  tab_name  |
    +------------+
    | mv_emp_dp  |
    +------------+

    Также проверьте директорию хранилища HDFS на наличие новых файлов:

    $ hdfs dfs -ls /apps/hive/warehouse/mv_demo.db/mv_emp_dp

    В хранилище Hive доступен новый ORC-файл с данными MV:

    -rw-r--r--   3 hive hadoop        795 2023-11-20 13:23 /apps/hive/warehouse/mv_demo.db/mv_emp_dp/000000_0
  3. Выполните запрос, аналогичный тому, что использовался для создания MV. Такой запрос получает результаты непосредственно из MV вместо соединения и сканирования двух исходных таблиц.

    SELECT e.last_name, e.email, d.dep_name
    FROM employees e JOIN departments d
    ON (e.dept_id = d.id)
    WHERE d.dep_name='sales';

    Результат:

    +--------------+-------------------------+-------------+
    | e.last_name  |         e.email         | d.dep_name  |
    +--------------+-------------------------+-------------+
    | Ivanov       | ivan_ivanov123@mail.ru  | sales       |
    +--------------+-------------------------+-------------++
  4. Выполните тот же запрос с предложением EXPLAIN EXTENDED для проверки переписывания запроса.

    EXPLAIN EXTENDED SELECT e.last_name, e.email, d.dep_name
    FROM employees e JOIN departments d
    ON (e.dept_id = d.id)
    WHERE d.dep_name='sales';

    Вывод показан ниже. Обратите внимание на alias: mv_demo.mv_emp_dp — данная запись означает, что результаты были получены из MV mv_demo.mv_emp_dp одним сканированием.

    +----------------------------------------------------+
    |                      Explain                       |
    +----------------------------------------------------+
    | STAGE DEPENDENCIES:                                |
    |   Stage-0 is a root stage                          |
    |                                                    |
    | STAGE PLANS:                                       |
    |   Stage: Stage-0                                   |
    |     Fetch Operator                                 |
    |       limit: -1                                    |
    |       Processor Tree:                              |
    |         TableScan                                  |
    |           alias: mv_demo.mv_emp_dp                 |
    |           GatherStats: false                       |
    |           Filter Operator                          |
    |             isSamplingPred: false                  |
    |             predicate: (dep_name = 'sales') (ty... |
    |             Select Operator                        |
    |               expressions: last_name (type: str... |
    |               outputColumnNames: _col0, _col1, ... |
    |               ListSink                             |
    |                                                    |
    +----------------------------------------------------+
  5. Обновите исходную таблицу.

    INSERT INTO employees VALUES
    (5,'Anna','Petrova','ann_pett@yandxed.ru', 32, 1700, 1);
  6. Еще раз выполните запрос с EXPLAIN EXTENDED:

    EXPLAIN EXTENDED SELECT e.last_name, e.email, d.dep_name
    FROM employees e JOIN departments d
    ON (e.dept_id = d.id)
    WHERE d.dep_name='sales';

    На этот раз план выполнения содержит этапы объединения и полного сканирования таблиц, так как содержимое mv_emp_dp MV отличается от исходных таблиц.

    +----------------------------------------------------+
    |                      Explain                       |
    +----------------------------------------------------+
    | STAGE DEPENDENCIES:                                |
    |   Stage-1 is a root stage                          |
    |   Stage-0 depends on stages: Stage-1               |
    |                                                    |
    | STAGE PLANS:                                       |
    |   Stage: Stage-1                                   |
    |     Tez                                            |
    |       DagId: hive_20231120144209_2c92e022-a865-... |
    |       Edges:                                       |
    |         Map 1 <- Map 2 (BROADCAST_EDGE)            |
    |       DagName: hive_20231120144209_2c92e022-a86... |
    |       Vertices:                                    |
    |         Map 1                                      |
    |             Map Operator Tree:                     |
    |                 TableScan                          |
    |                   alias: e                         |
    |                   Statistics: Num rows: 50 Dat ... |
    |                   ...                              |
    +----------------------------------------------------+
  7. Чтобы синхронизировать изменения в исходных таблицах и MV, перестройте MV:

    ALTER MATERIALIZED VIEW mv_emp_dp REBUILD;
  8. Выполните запрос с EXPLAIN EXTENDED:

    EXPLAIN EXTENDED SELECT e.last_name, e.email, d.dep_name
    FROM employees e JOIN departments d
    ON (e.dept_id = d.id)
    WHERE d.dep_name='sales';

    Теперь в плане выполнения содержится информация об использовании MV для получения данных.

    +----------------------------------------------------+
    |                      Explain                       |
    +----------------------------------------------------+
    | STAGE DEPENDENCIES:                                |
    |   Stage-0 is a root stage                          |
    |                                                    |
    | STAGE PLANS:                                       |
    |   Stage: Stage-0                                   |
    |     Fetch Operator                                 |
    |       limit: -1                                    |
    |       Processor Tree:                              |
    |         TableScan                                  |
    |           alias: mv_demo.mv_emp_dp                 |
    |           GatherStats: false                       |
    |           Filter Operator                          |
    |             isSamplingPred: false                  |
    |             predicate: (dep_name = 'sales') (ty... |
    |             Select Operator                        |
    |               expressions: last_name (type: str... |
    |               outputColumnNames: _col0, _col1, ... |
    |               ListSink                             |
    |                                                    |
    +----------------------------------------------------+
  9. Для удаления MV используйте команду:

    DROP MATERIALIZED VIEW mv_emp_dp;
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней