---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.6
alternate:
  - https://ytsaurus.tech/docs/en/user-guide/data-processing/chyt/reference/performance.md
  - https://ytsaurus.tech/docs/ru/user-guide/data-processing/chyt/reference/performance.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ytsaurus.tech/docs/ru/llms.txt

<!-- source: ru/_includes/user-guide/data-processing/chyt/reference/performance.md -->
# Производительность и рекомендации

При выборе между CH и CHYT возникает вопрос — что быстрее и насколько?

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

Данные в YTsaurus изначально не предназначены для выполнения OLAP-запросов. Чтобы получить нормальную скорость, нужно их подготовить.
Добиться скорости CH, скорее всего, не получится, но можно приблизиться, правильно выбирая схему хранения данных и запросов к ним.
Зато неправильным хранением данных легко можно добиться скорости запросов в сотни раз ниже чем в CH.


## На что уходит время { #where_my_time }

Ниже приведены этапы выполнения запроса, которые могут быть "узким местом".

1. Чтение метаинформации таблиц и чанков, распределение запроса по инстансам.
2. Чтение данных с диска.
3. Передача данных по сети.
4. Расжатие данных и декодирование.
5. Merge версий (только для [динамических](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/overview.md) таблиц).
6. Конвертация данных из формата YTsaurus в формат CH.
7. Обработка данных движком ClickHouse.
8. Конвертирование данных из формата CH в формат YTsaurus (только для операций записи).
9. Запись данных в YTsaurus (только для операций записи).

В зависимости от того, как данные хранятся и какими запросами обрабатываются, разные этапы могут быть узким местом.

## Чтение данных { #read }

Далее описаны факторы, влияющие на скорость запросов чтения.

### Размер обрабатываемых данных { #data_weight }

В первую очередь CHYT заточен для быстрой обработки (порядка секунд) данных малого (порядка ГБ) и среднего (порядка десятков ГБ) размера. Эффективно использовать CHYT для обработки ТБ данных не получится. Уменьшить количество обрабатываемых данных можно с помощью правильной [схемы](https://ytsaurus.tech/docs/ru/user-guide/storage/static-schema.md) хранения данных (используя поколоночность и сортированность).

Для построения дашбордов поверх большого объема данных рекомендуется делать отдельные таблицы с "выжимкой" нужных данных, а так же предагрегированными значениями. Например, если данные в миллисекундах, а аналитику нужно строить по дням, то нужно предагрегировать данные до дня.

Как уменьшить количество вычислений налету:
* Например, дату можно считать по полю `datetime`, но фильтрация по этому полю будет медленнее.
* Избегать выполнения неоправданно тяжелых запросов. Например, сортировка 100ГБ, `SELECT DISTINCT` или `GROUP BY` по колонке, которая имеет миллионы различных значений, или использование оператора `JOIN` для больших таблиц. Такие запросы всегда будут обрабатываться медленно.

Чтение больших таблиц может упереться в любой пункт исполнения запроса из списка выше.

### Erasure кодирование { #erasure }

Erasure кодирование предназначено для "холодных" таблиц. Данные в erasure кодировании занимают меньше дискового пространства, но это негативно сказывается на скорости чтении таких данных:
1. Каждый чанк разбит на 16 (или 9 в зависимости от алгоритма кодирования) частей, что увеличивает количество метаинформации (пункт 1).
2. Данные хранятся в одной копии, поэтому чтение нельзя распараллелить (пункт 2).
3. В случае, если диск на ноде загружен, не будет возможности переключиться на чтение данных с другой ноды. А так как чанк разбит на 16 частей, то вероятность что чтение хотя бы одного их них зависнет сильно увеличивается.
4. Если данные недоступны из-за сбоя узла кластера, их необходимо восстанавливать. Это достаточно долгий и ресурсозатратный процесс. (пункт 2, 4?).

Как результат, чтение данных с erasure кодированием занимает в разы больше времени, а задержки при чтении становятся более вероятными и менее предсказуемыми. Строить дашборды или делать другие регулярные запросы поверх данных в erasure кодированием **крайне не рекомендуется**.

### Формат хранения данных { #optimize_for }
Данные в YTsaurus таблицах могут храниться как в построчном (`optimize_for=lookup`), так и в поколоночном (`optimize_for=scan`) формате.

{% note warning "Внимание" %}

ClickHouse — это колоночная СУБД, поэтому настоятельно рекомендуется использовать именно поколоночное хранение.

{% endnote %}

Поколоночное хранение данных имеет следующие преимущества:
- Конвертация данных в формат CH из поколоночного формата YTsaurus в разы (если не в десятки раз) эффективнее, чем из построчного (пункт 6).
- При поколоночном хранении данных во время запроса будут считаны только запрошенные колонки. (пункты 2, 3 и 4).
- Данные, хранящиеся поколоночно, лучше сжимаются, поэтому занимают меньше места (пункты 2, 3).

{% note info %}

Обычная смена аттрибутов `optimize_for/erasure_codec` не перекладывает старые данные в новый формат. Чтобы изменение формата случилось, запустите операцию `merge` с опцией `force_transform=%true`.

{% endnote %}


### Ключевые колонки { #key_columns }

Для эффективного чтения в ClickHouse существуют индексы и ключи шардирования. В YTsaurus модель хранения данных немного иная, привычных индексов нет. Но есть сортированные таблицы. Запросы над сортированными таблицами используют ключ сортировки как первичный индекс (Primary key) и ключ шардирования (Sharding key).

Это позволяет:
- эффективно фильтровать и не читать лишние данные с диска (пункт 2).
- эффективнее делать запрос, в частности, `Sorted Join`.
- лучше сжимать сортированные таблицы, в результате чего они занимают меньше места (пункт 2).

Выбирать ключ сортировки нужно в зависимости от запросов:

- Например, если запросы выглядит как
``` ... where date between '2021-01-01' and '2021-02-01'```

Хорошим ключом будет `date`.

- Для запросов вида
``` ... where user_id = 1234```
Хорошим ключом будет `user_id`.

В некоторых случаях, если отсортировать таблицу, эффективной фильтрации не будет. Колонка строковая и конвертация `DateTime` <-> `String` не является монотонной и однозначной. Преобразование `Int` <-> `DateTime` монотонное, но со строковым представлением применять такую оптимизацию в общем случае нельзя. Например, `2020-01-01 00:00:00` и `2020-01-01T00:00:00` — корректное представление одного и того же момента времени в ClickHouse, но при сортировке со строковым представлением между ними может появиться значение `2020-01-01 00:00:01`, поэтому преобразование `String` -> `DateTime` не является монотонным и использовать эту оптимизацию нельзя.

### Количество чанков { #chunk_count }

Количество чанков влияет на несколько этапов выполнения запроса.

Чем больше количество чанков у таблицы, тем больше необходимо считать метаинформации на шаге 1. Если у таблицы тысячи чанков — считывание метаинформации может затянуться на несколько секунд. Если чанков много у очень маленькой таблицы, то чтение каждого чанка превращается в random read и может работать медленно (шаг 2).
С другой стороны, если чанков слишком мало (например, 1 чанк на 10 GB), то все данных хранятся на одних и тех же дисках, что ограничит параллельность чтения на шаге 2.

Для укрупнения чанков используйте операцию `Merge`.

### Количество входных таблиц { #table_count }

Аналогично количеству чанков, но метаинформация для таблицы в разы тяжелее чем метаинформация для чанка. Кроме того, для каждой таблицы нужно отдельно проверить права доступа. Рекомендуем делать не более сотен таблиц. Желательно объединять много таблиц в одну большую.

### Количество колонок { #column_count }

Количество колонок в таблице тоже влияет на скорость работы с данными, даже если данные хранятся в поколоночном формате. Размер блока подбирается так, что бы ридер мог считать по блоку для каждой колонки и выдать результат. Что бы при таком чтении данные влезали в память, при увеличении числа колонок размер блоков уменьшается. При совсем маленьких блоках чтение превращается в random read (шаг 2). Рекомендуем иметь десятки, максимум 100 колонок. Тысячи колонок гарантированно будут работать плохо.
Кроме того, большое количество колонок увеличивает количество метаинформации на шаге 1.

### Динамические vs Статические таблицы { #dyn-vs-stat }

Данные в динамических таблицах хранятся по-другому и не предназначены для full-scan-чтения. Это накладывает дополнительные расходы на их чтение:

1. Во-первых, нужно читать для каждого значения его версию.
2. Во-вторых, для каждой строчки необходимо прочитать все ключевые колонки, даже если они не используются в запросе.
3. Далее, необходимо сделать объединение всех строчек с одинаковым ключом, оставив только 1 самую свежую версию. Это очень тяжелый процесс с большим количеством сравнений. Кроме того, процесс сугубо построчный, поэтому даже если данные хранятся поколоночно, их придется переложить построчно.
4. После этого необходимо переложить данные обратно в поколоночный формат.

`Merge` может добавлять x10 к времени чтения данных.

Строить дашборды или делать другие регулярные запросы поверх динамических таблиц большого размера крайне не рекомендуется ввиду неэффективности чтения.

### SSD vs HDD { #ssd_vs_hdd }

SSD диски обладают очевидным преимуществом — большей скоростью чтения и меньшими задержками на шаге 2.

### Optional колонки { #optional_columns }

Большинство колонок в YTsaurus являются опциональными (`required: false`), то есть вместо значения может храниться `Null`. В CH это не так, большинство колонок не являются `Nullable`. Использования опциональных колонок замедляет практически все стадии, от чтения и конвертации данных до обработки в CH.

Рекомендуется ставить более жесткую схему и избавляться от optional колонок там, где нет такой необходимости.

### Кеши данных { #data_caches }

В CHYT есть большое количество кешей, ускоряющих те или иные стадии выполнения запроса.
Самые главные — `compressed_block_cache` и `uncompressed_block_cache`. Использование второго избавляет от этапов 2 и 3. Использование первого — от этапов 2, 3 и 4 (разжатие).
Маленькие таблицы скорее всего будут всегда читаться из кеша.
<!-- endsource: ru/_includes/user-guide/data-processing/chyt/reference/performance.md -->