Перейти к основному содержимому
Перейти к основному содержимому

Производительность запросов временных рядов

После оптимизации хранения следующим шагом является улучшение производительности запросов. В этом разделе рассматриваются две ключевые техники: оптимизация ключей ORDER BY и использование материализованных представлений. Мы увидим, как эти подходы могут сократить время выполнения запросов с секунд до миллисекунд.

Оптимизация ключей ORDER BY

Перед тем, как пытаться проводить другие оптимизации, вам следует оптимизировать их ключ сортировки, чтобы гарантировать, что ClickHouse будет выдавать максимально быстрые результаты. Выбор правильного ключа в значительной степени зависит от запросов, которые вы собираетесь выполнять. Предположим, что большинство наших запросов фильтрует по колонкам project и subproject. В этом случае хорошей идеей будет добавить их в ключ сортировки - наряду с колонкой времени, поскольку мы также запрашиваем по времени:

Создадим другую версию таблицы, которая имеет те же типы колонок, что и wikistat, но отсортирована по (project, subproject, time).

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

Запрос(time)(project, subproject, time)
2.381 сек1.660 сек
2.148 сек0.058 сек
2.192 сек0.012 сек
2.968 сек0.010 сек

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

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

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

Мы можем создать следующее материализованное представление:

Заполнение целевой таблицы

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

Самый простой способ сделать это - использовать оператор INSERT INTO SELECT, чтобы вставить непосредственно в целевую таблицу материализованного представления, используя (https://github.com/ClickHouse/examples/tree/main/ClickHouse_vs_ElasticSearch/DataAnalytics#variant-1---directly-inserting-into-the-target-table-by-using-the-materialized-views-transformation-query) запрос SELECT материализованного представления (преобразование):

В зависимости от кардинальности исходного набора данных (у нас 1 миллиард строк!), этот подход может потребовать значительных ресурсов памяти. Альтернативно, вы можете использовать вариант, который требует минимального объема памяти:

  • Создание временной таблицы с движком Null
  • Подключение копии обычно используемого материализованного представления к этой временной таблице
  • Использование запроса INSERT INTO SELECT, копируя все данные из исходного набора данных в эту временную таблицу
  • Удаление временной таблицы и временного материализованного представления.

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

Затем мы создадим материализованное представление, которое будет читать из wikistat_backfill и записывать в wikistat_top

И затем, наконец, мы заполним wikistat_backfill из начальной таблицы wikistat:

Как только этот запрос завершится, мы можем удалить таблицу дозаполнения и материализованное представление:

Теперь мы можем запрашивать материализованное представление вместо оригинальной таблицы:

Наша производительность здесь существенно улучшилась. Ранее для вычисления ответа на этот запрос требовалось чуть больше 2 секунд, а теперь он занимает всего 4 миллисекунды.