Введение
Основной принцип работы
- Имя индекса. Имя индекса используется для создания файла индекса в каждой партиции. Оно также требуется как параметр при удалении или материализации индекса.
- Выражение индекса. Выражение индекса используется для вычисления набора значений, хранящихся в индексе. Это может быть комбинация столбцов, простых операторов и/или подмножества функций, определяемого типом индекса.
- TYPE. Тип индекса определяет вычисление, по результатам которого решается, можно ли пропустить чтение и обработку каждого блока индекса.
- GRANULARITY. Каждый индексируемый блок состоит из GRANULARITY гранул. Например, если гранулярность первичного индекса таблицы составляет 8192 строки, а гранулярность индекса — 4, то каждый индексируемый “блок” будет содержать 32768 строк.
skp_idx_{index_name}.idx, который содержит упорядоченные значения выраженияskp_idx_{index_name}.mrk2, который содержит соответствующие смещения в связанных файлах столбцов.
my_value:
my_value равно 125, а следующие строки
были пропущены без чтения с диска:
Подробную информацию об использовании индекса пропуска данных можно получить, включив trace при выполнении запросов. В
clickhouse-client задайте send_logs_level:
Типы индексов пропуска данных
minmax
set
text
hasAnyToken и hasAllTokens, а также оптимизирует все распространённые функции текстового поиска.
Подробности см. в документации по текстовому индексу здесь.
Типы bloom-фильтров
- Базовый bloom_filter, который принимает один необязательный параметр — допустимую вероятность ложноположительных срабатываний в диапазоне от 0 до 1 (если параметр не указан, используется .025).
-
Специализированный tokenbf_v1 (Устарело)). Он принимает три параметра, все они относятся к настройке используемого bloom-фильтра: (1) размер фильтра в байтах (чем больше фильтр, тем меньше ложноположительных срабатываний, но тем больше затраты на хранение), (2) количество применяемых хеш-функций (чем их больше, тем ниже вероятность ложноположительных срабатываний) и (3) seed для хеш-функций bloom-фильтра. Подробнее о том, как эти параметры влияют на работу bloom-фильтра, см. в калькуляторе здесь.
Этот индекс работает только с типами данных String, FixedString и Map. Входное выражение разбивается на последовательности символов, разделённые неалфавитно-цифровыми символами. Например, значение столбца
This is a candidate for a \"full text\" searchбудет содержать токеныThisisacandidateforfulltextsearch. Он предназначен для использования в LIKE, EQUALS, IN, hasToken() и аналогичных поисковых запросах по словам и другим значениям внутри более длинных строк. Например, его можно использовать для поиска небольшого числа имён классов или номеров строк в столбце с произвольными строками журналов приложения. -
Специализированный ngrambf_v1 (Устарело). Этот индекс работает так же, как token-индекс. Он принимает ещё один параметр перед настройками bloom-фильтра — размер n-грамм для индексации. N-грамма — это строка длиной
nиз любых символов, поэтому строкаA short stringпри размере n-граммы 4 будет индексироваться как:
Для рабочих нагрузок полнотекстового поиска рекомендуется использовать специализированный текстовый индекс (см. Text index for full-text search) вместо устаревших индексов tokenbf_v1 или ngrambf_v1. Текстовый индекс предоставляет полноценный инвертированный индекс с более высокой производительностью поиска, более предсказуемым поведением, а также большей гибкостью и производительностью по сравнению с индексами bloom-фильтра на основе токенов.
Функции индексов пропуска данных
- данные вставляются, и индекс определен как функциональное выражение (при этом результат выражения сохраняется в файлах индекса), или
- обрабатывается запрос, и выражение применяется к сохраненным значениям индекса, чтобы определить, нужно ли исключить блок.
Настройки индексов пропуска данных
- use_skip_indexes (0 или 1, по умолчанию 1). Не все запросы могут эффективно использовать индексы пропуска данных. Если определённое условие фильтрации, скорее всего, охватывает большинство гранул, применение индекса пропуска данных влечёт за собой лишние, а иногда и существенные, затраты. Установите значение 0 для запросов, которым индексы пропуска данных, скорее всего, не дадут выигрыша.
- force_data_skipping_indices (список имён индексов, разделённых запятыми). Эту настройку можно использовать, чтобы предотвратить некоторые виды неэффективных запросов. Если запрос к таблице становится слишком затратным без использования индекса пропуска данных, то при использовании этой настройки с одним или несколькими именами индексов для любого запроса, который не использует указанный индекс, будет возвращено исключение. Это не позволит неудачно написанным запросам расходовать ресурсы сервера.
Рекомендации по использованию индекса пропуска данных
timestamp, и есть индекс по visitor_id. Рассмотрим следующий запрос:
visitor_id будут проверены
независимо от типа индекса пропуска данных.
Соответственно, естественное стремление ускорить запросы ClickHouse, просто добавив индекс к ключевым
столбцам, часто оказывается ошибочным. Эту продвинутую возможность следует использовать только после рассмотрения других альтернатив, таких как изменение первичного ключа (см. Как выбрать первичный ключ), использование проекций или materialized view. Даже когда индекс пропуска данных уместен, часто
требуется тщательная настройка как самого индекса, так и таблицы.
В большинстве случаев полезный индекс пропуска данных требует сильной корреляции между первичным ключом и целевым неключевым столбцом/выражением.
Если корреляции нет (как на диаграмме выше), высока вероятность того, что условию фильтрации будет соответствовать хотя бы одна из строк в
блоке из нескольких тысяч значений, и тогда удастся пропустить лишь немного блоков. Напротив, если диапазон значений первичного ключа (например, время
суток) тесно связан со значениями в потенциально индексируемом столбце (например, возрастом телезрителей), то индекс
типа minmax, скорее всего, окажется полезным. Обратите внимание, что эту корреляцию можно усилить при вставке данных: либо включив дополнительные
столбцы в ключ сортировки/ORDER BY, либо организовав батчинг вставок так, чтобы значения, связанные с первичным ключом, группировались при вставке. Например,
все события для определённого site_id можно сгруппировать и вставить вместе в процессе приёма, даже если первичный ключ
— это временная метка, содержащая события с большого числа сайтов. Это приведёт к появлению множества гранул, содержащих лишь несколько site ids, поэтому многие
блоки можно будет пропустить при поиске по конкретному значению site_id.
Ещё один хороший кандидат для индекса пропуска данных — выражения с высокой мощностью, где каждое отдельное значение встречается в данных относительно редко. Например,
это может быть платформа обсервабилити, которая отслеживает коды ошибок в API-запросах. Некоторые коды ошибок, хотя и редко встречаются в данных, могут быть особенно
важны для поиска. Индекс пропуска данных типа set для столбца error_code позволит обходить подавляющее большинство блоков, которые не содержат
ошибок, и тем самым значительно ускорит запросы, ориентированные на ошибки.
Наконец, главная рекомендация — тестировать, тестировать и ещё раз тестировать. Опять же, в отличие от вторичных b-tree индексов или инвертированных индексов для поиска по документам,
поведение индекса пропуска данных нелегко предсказать. Их добавление в таблицу влечёт заметные издержки как для приёма данных, так и для запросов,
которые по тем или иным причинам не получают выгоды от индекса. Их всегда следует тестировать на данных, близких к реальным, а тестирование должно
включать вариации типа, размера гранулярности и других параметров. Тестирование часто выявляет закономерности и подводные камни, которые неочевидны при
одних лишь мысленных экспериментах.