Skip to main content
Этот раздел посвящён оптимизации производительности при чтении и вставке данных из S3 с помощью табличных функций s3.
Описанный в этом руководстве подход можно применять и к другим реализациям объектного хранилища с собственными специализированными табличными функциями, таким как GCS и Azure Blob storage.
Прежде чем настраивать число потоков и размер блоков для повышения производительности вставки, рекомендуем разобраться в механике вставки в S3. Если вы уже с ней знакомы или просто хотите получить несколько быстрых рекомендаций, перейдите к примеру ниже.

Механика вставки (один узел)

Помимо характеристик оборудования, на производительность и потребление ресурсов при вставке данных в ClickHouse (на одном узле) влияют два основных фактора: размер блока вставки и параллелизм вставки.

Размер блока вставки

При выполнении INSERT INTO SELECT ClickHouse получает некоторую порцию данных и ① формирует из неё (как минимум) один блок вставки в памяти (для каждого ключа партиционирования). Данные в блоке сортируются, и к ним применяются оптимизации, специфичные для движка таблицы. Затем данные сжимаются и ② записываются в хранилище базы данных в виде новой части данных. Размер блока вставки влияет как на дисковый файловый ввод-вывод, так и на потребление памяти сервером ClickHouse. Более крупные блоки вставки требуют больше памяти, но создают более крупные и менее многочисленные исходные части. Чем меньше частей ClickHouse нужно создать для загрузки большого объёма данных, тем меньше требуется дискового ввода-вывода и автоматических фоновых слияний. При использовании запроса INSERT INTO SELECT в сочетании с движком интеграционной таблицы или табличной функцией данные загружаются сервером ClickHouse: Пока данные не будут полностью загружены, сервер выполняет цикл:
В ① размер зависит от размера блока вставки, которым можно управлять с помощью двух настроек: Когда в блоке вставки набирается либо указанное количество строк, либо достигается заданный объём данных (в зависимости от того, что произойдёт раньше), блок записывается в новую часть. Цикл вставки продолжается с шага ①. Обратите внимание, что значение min_insert_block_size_bytes обозначает размер несжатого блока в памяти (а не размер сжатой части на диске). Также обратите внимание, что созданные блоки и части редко содержат в точности заданное количество строк или байтов, поскольку ClickHouse обрабатывает данные в потоковом режиме, построчно-блоками. Поэтому эти настройки задают минимальные пороговые значения.

Учитывайте слияния

Чем меньше заданный размер блока вставки, тем больше исходных частей создаётся при большой загрузке данных и тем больше фоновых слияний частей выполняется одновременно с приёмом данных. Это может приводить к конкуренции за ресурсы (CPU и память) и требовать дополнительного времени после завершения загрузки, чтобы число частей вернулось к приемлемому уровню (3000).
Производительность запросов ClickHouse снизится, если количество частей превысит рекомендуемые пределы.
ClickHouse будет непрерывно сливать части в более крупные, пока они не достигнут сжатого размера около 150 GiB. Эта диаграмма показывает, как сервер ClickHouse сливает части: Один сервер ClickHouse использует несколько фоновых потоков слияния для выполнения параллельных слияний частей. Каждый поток выполняет цикл:
Обратите внимание, что увеличение числа ядер CPU и объема RAM повышает производительность фоновых слияний. Части, слитые в более крупные, помечаются как неактивные и в итоге удаляются через настраиваемое количество минут. Со временем это формирует дерево слитых частей (отсюда и название таблицы MergeTree).

Параллелизм вставки

Сервер ClickHouse может обрабатывать и вставлять данные параллельно. Уровень параллелизма вставки влияет на пропускную способность ингестии и потребление памяти сервером ClickHouse. Параллельная загрузка и обработка данных требует больше оперативной памяти, но повышает пропускную способность ингестии, поскольку данные обрабатываются быстрее. Табличные функции, такие как s3, позволяют задавать наборы имён файлов для загрузки с помощью glob-шаблонов. Если glob-шаблон соответствует нескольким существующим файлам, ClickHouse может распараллеливать чтение как между этими файлами, так и внутри них, а также параллельно вставлять данные в таблицу, используя одновременно работающие потоки вставки (на сервер): Пока не будут обработаны все данные из всех файлов, каждый поток вставки выполняет следующий цикл:
Количество таких параллельных потоков вставки можно настроить с помощью параметра max_insert_threads. Значение по умолчанию — 1 для open-source ClickHouse и 4 для ClickHouse Cloud. При большом количестве файлов параллельная обработка несколькими потоками вставки работает эффективно. Она может полностью загрузить как доступные ядра CPU, так и пропускную способность сети (при параллельной загрузке файлов). В сценариях, когда в таблицу загружается всего несколько крупных файлов, ClickHouse автоматически обеспечивает высокий уровень параллелизма обработки данных и оптимизирует использование пропускной способности сети, создавая дополнительные потоки чтения для каждого потока вставки, чтобы параллельно читать (загружать) разные диапазоны внутри крупных файлов. Для функции и таблицы s3 параллельная загрузка отдельного файла определяется значениями max_download_threads и max_download_buffer_size. Файлы будут загружаться параллельно, только если их размер превышает 2 * max_download_buffer_size. По умолчанию значение max_download_buffer_size равно 10 MiB. В некоторых случаях можно без риска увеличить размер этого буфера до 50 MB (max_download_buffer_size=52428800), чтобы каждый файл загружался одним потоком. Это может сократить время, которое каждый поток тратит на обращения к S3, и тем самым уменьшить время ожидания S3. Кроме того, для файлов, слишком маленьких для параллельного чтения, ClickHouse для повышения пропускной способности автоматически выполняет предзагрузку данных, асинхронно читая такие файлы заранее.

Измерение производительности

Оптимизация производительности запросов при использовании табличных функций S3 важна как при выполнении запросов непосредственно к данным, то есть при ad-hoc-запросах, когда используются только вычислительные ресурсы ClickHouse, а данные остаются в S3 в исходном формате, так и при вставке данных из S3 в таблицу ClickHouse на движке MergeTree. Если не указано иное, следующие рекомендации относятся к обоим сценариям.

Влияние конфигурации оборудования

Количество доступных ядер процессора и объём оперативной памяти влияют на: и, следовательно, на общую скорость загрузки данных.

Один и тот же регион

Убедитесь, что ваши бакеты находятся в том же регионе, что и экземпляры ClickHouse. Эта простая оптимизация может существенно повысить пропускную способность, особенно если вы развертываете экземпляры ClickHouse в инфраструктуре AWS.

Форматы

ClickHouse может читать файлы, хранящиеся в бакетах S3, в поддерживаемых форматах, используя функцию s3 и движок S3. При чтении сырых файлов некоторые из этих форматов имеют явные преимущества:
  • Форматы с закодированными именами столбцов, такие как Native, Parquet, CSVWithNames и TabSeparatedWithNames, делают запросы менее многословными, поскольку пользователю не нужно указывать имена столбцов в функции s3. Эта информация определяется автоматически по именам столбцов.
  • Форматы различаются по производительности чтения и записи. Native и Parquet — наиболее оптимальные форматы для чтения, поскольку они изначально являются колоночными и более компактны. Формат Native дополнительно выигрывает за счет того, что соответствует тому, как ClickHouse хранит данные в памяти, — это снижает накладные расходы на обработку при потоковой загрузке данных в ClickHouse.
  • Размер блока часто влияет на задержку при чтении больших файлов. Это особенно заметно, если вам нужна лишь выборка данных, например первые N строк. В случае форматов вроде CSV и TSV, чтобы вернуть набор строк, файл необходимо полностью разобрать. Форматы вроде Native и Parquet позволяют делать такую выборку быстрее.
  • У каждого формата сжатия есть свои плюсы и минусы: обычно это компромисс между степенью сжатия и скоростью, с акцентом либо на производительность сжатия, либо на скорость распаковки. Если вы сжимаете сырые файлы, такие как CSV или TSV, lz4 обеспечивает самую быструю распаковку, жертвуя степенью сжатия. Gzip обычно сжимает лучше, но скорость чтения при этом немного ниже. Xz идет еще дальше и обычно обеспечивает наилучшее сжатие, но при самой низкой скорости сжатия и распаковки. При экспорте Gz и lz4 дают сопоставимую скорость сжатия. Соотносите это со скоростью вашего соединения. Любой выигрыш от более быстрой распаковки или сжатия легко может быть сведен на нет медленным соединением с вашими бакетами S3.
  • Такие форматы, как Native или Parquet, обычно не оправдывают дополнительные затраты на сжатие. Экономия места, скорее всего, будет минимальной, поскольку эти форматы сами по себе компактны. Время, затраченное на сжатие и распаковку, редко компенсирует время передачи по сети — особенно с учетом того, что S3 доступен по всему миру и обычно обеспечивает высокую пропускную способность.

Пример набора данных

Чтобы нагляднее показать возможные оптимизации, мы будем использовать посты из набора данных Stack Overflow и оптимизировать для этих данных как производительность запросов, так и скорость вставки. Этот набор данных состоит из 189 файлов Parquet — по одному на каждый месяц с июля 2008 года по март 2024 года. Обратите внимание, что для повышения производительности мы используем Parquet в соответствии с нашими рекомендациями выше и выполняем все запросы на кластере ClickHouse, расположенном в том же регионе, что и бакет. Этот кластер состоит из 3 узлов, каждый из которых имеет 32 GiB RAM и 8 vCPU. Без какой-либо дополнительной настройки мы покажем производительность вставки этого набора данных в таблицу на движке MergeTree, а также выполнения запроса для определения пользователей, задающих больше всего вопросов. Оба этих запроса намеренно требуют полного сканирования данных.
В нашем примере мы возвращаем лишь несколько строк. Если вы измеряете производительность запросов SELECT, которые возвращают клиенту большие объёмы данных, используйте для запросов либо формат Null, либо направляйте результаты в движок Null. Это поможет избежать перегрузки клиента данными и насыщения сети.
При выполнении запросов на чтение первый запрос часто может казаться медленнее, чем повторное выполнение того же запроса. Это может быть связано как с собственным кэшированием S3, так и с кэшем вывода схемы ClickHouse. В нём сохраняется выведенная схема файлов, благодаря чему при последующих обращениях можно пропустить этап вывода схемы и тем самым сократить время выполнения запроса.

Использование потоков для чтения

Производительность чтения из S3 будет линейно расти с увеличением числа ядер, если только вы не упираетесь в пропускную способность сети или локального I/O. Увеличение числа потоков также ведет к дополнительным затратам памяти, о которых следует помнить. Для потенциального повышения пропускной способности чтения можно изменить следующее:
  • Обычно значения max_threads по умолчанию достаточно, то есть числа ядер. Если запрос потребляет много памяти и это нужно сократить, либо если LIMIT для результатов невелик, это значение можно уменьшить. Пользователи с большим объемом памяти могут поэкспериментировать с увеличением этого значения, чтобы, возможно, добиться более высокой пропускной способности чтения из S3. Как правило, это полезно только на машинах с небольшим числом ядер, то есть < 10. Выигрыш от дальнейшей параллелизации обычно снижается, поскольку другие ресурсы становятся узким местом, например сеть и конкуренция за CPU.
  • Версии ClickHouse до 22.3.1 распараллеливали чтение только между несколькими файлами при использовании функции s3 или табличного движка S3. Это требовало от пользователя разбивать файлы на части в S3 и читать их с использованием glob-шаблона, чтобы добиться оптимальной производительности чтения. В более поздних версиях загрузки теперь распараллеливаются и внутри одного файла.
  • В сценариях с небольшим числом потоков может помочь установка remote_filesystem_read_method в значение “read”, чтобы включить синхронное чтение файлов из S3.
  • Для функции s3 и таблицы параллельная загрузка отдельного файла определяется значениями max_download_threads и max_download_buffer_size. Хотя max_download_threads управляет числом используемых потоков, файлы будут загружаться параллельно только в том случае, если их размер превышает 2 * max_download_buffer_size. По умолчанию значение max_download_buffer_size равно 10MiB. В некоторых случаях можно безопасно увеличить размер этого буфера до 50 MB (max_download_buffer_size=52428800), чтобы небольшие файлы загружались только одним потоком. Это может сократить время, которое каждый поток тратит на вызовы S3, и тем самым уменьшить время ожидания S3. Пример см. в этой записи блога.
Прежде чем вносить какие-либо изменения для повышения производительности, обязательно проведите соответствующие замеры. Поскольку вызовы API S3 чувствительны к задержке и могут влиять на время выполнения на стороне клиента, используйте для метрик производительности журнал запросов, то есть system.query_log. Рассмотрим наш предыдущий запрос: удвоение max_threads до 16 (значение max_thread по умолчанию равно числу ядер на узле) повышает производительность запроса на чтение в 2 раза ценой большего потребления памяти. Дальнейшее увеличение max_threads дает все меньший эффект, как показано.

Настройка потоков и размера блоков для вставки

Чтобы добиться максимальной производительности загрузки, необходимо выбрать (1) размер блока вставки и (2) подходящий уровень параллелизма вставки с учётом (3) количества доступных ядер CPU и объёма доступной RAM. Вкратце: Между этими двумя факторами производительности существует компромисс (как и компромисс с фоновым слиянием частей). Объём доступной оперативной памяти на серверах ClickHouse ограничен. Более крупные блоки занимают больше оперативной памяти, а это ограничивает количество параллельных потоков вставки, которые можно задействовать. И наоборот, большее число параллельных потоков вставки требует больше оперативной памяти, поскольку именно число потоков вставки определяет, сколько блоков вставки одновременно создаётся в памяти. Это, в свою очередь, ограничивает возможный размер блоков вставки. Кроме того, между потоками вставки и потоками фонового слияния может возникать конкуренция за ресурсы. Большое число настроенных потоков вставки (1) создаёт больше частей, которые затем нужно сливать, и (2) отнимает у потоков фонового слияния ядра CPU и оперативную память. Подробное описание того, как эти параметры влияют на производительность и потребление ресурсов, рекомендуем прочитать в этом посте блога. Как показано в этом посте, настройка может потребовать тщательного подбора баланса между этими двумя параметрами. Такое всестороннее тестирование часто оказывается непрактичным, поэтому в качестве краткой рекомендации мы советуем:
С помощью этой формулы можно установить min_insert_block_size_rows в 0 (чтобы отключить порог по числу строк), задать max_insert_threads нужным значением, а min_insert_block_size_bytes — значением, вычисленным по приведённой выше формуле. Применим эту формулу к нашему предыдущему примеру со Stack Overflow.
  • max_insert_threads=4 (8 ядер на узел)
  • peak_memory_usage_in_bytes — 32 GiB (100% ресурсов узла) или 34359738368 байт.
  • min_insert_block_size_bytes = 34359738368/(3*4) = 2863311530
Как видно, настройка этих параметров повысила производительность вставки более чем на 33%. Предлагаем читателю проверить, удастся ли ему ещё больше повысить производительность на одном узле.

Масштабирование за счёт ресурсов и узлов

Масштабирование за счёт ресурсов и узлов применимо как к запросам на чтение, так и к запросам на вставку.

Вертикальное масштабирование

Во всех предыдущих настройках и запросах использовался только один узел в нашем кластере ClickHouse Cloud. При этом в вашем распоряжении нередко будет несколько узлов ClickHouse. Мы рекомендуем сначала использовать вертикальное масштабирование, поскольку пропускная способность S3 линейно растет с увеличением числа ядер. Если повторить наши предыдущие запросы на вставку и чтение на более крупном узле ClickHouse Cloud с удвоенными ресурсами (64GiB, 16 vCPUs) и соответствующими настройками, оба запроса будут выполняться примерно в два раза быстрее.
Производительность отдельных узлов также может упираться в ограничения сети и S3 GET-запросов, что не позволяет добиваться линного прироста производительности при вертикальном масштабировании.

Горизонтальное масштабирование

Со временем горизонтальное масштабирование часто становится необходимым из-за доступности оборудования и экономической целесообразности. В ClickHouse Cloud производственные кластеры включают как минимум 3 узла. Поэтому для вставки данных может иметь смысл задействовать все узлы. Чтобы использовать кластер при чтении из S3, нужно применять функцию s3Cluster, как описано в разделе Использование кластеров. Это позволяет распределять чтение между узлами. Сервер, который первым получает запрос на вставку, сначала разворачивает glob-шаблон, а затем динамически распределяет обработку каждого подходящего файла между собой и другими серверами. Повторим предыдущий запрос на чтение, распределив нагрузку между 3 узлами и изменив запрос так, чтобы использовать s3Cluster. В ClickHouse Cloud это делается автоматически — достаточно указать кластер default. Как отмечено в разделе Использование кластеров, эта работа распределяется на уровне файлов. Чтобы воспользоваться этой возможностью, потребуется достаточное количество файлов, то есть как минимум больше, чем число узлов.
Аналогично, наш запрос INSERT можно выполнять в распределённом режиме, используя улучшенные настройки, ранее определённые для одного узла:
Читатели заметят, что чтение файлов улучшило производительность запросов, но не вставки. По умолчанию, хотя операции чтения распределяются с помощью s3Cluster, вставка выполняется через узел-инициатор. Это означает, что, хотя чтение происходит на каждом узле, полученные строки для распределения направляются на узел-инициатор. В сценариях с высокой пропускной способностью это может стать узким местом. Чтобы решить эту проблему, задайте параметр parallel_distributed_insert_select для функции s3cluster. Значение parallel_distributed_insert_select=2 гарантирует, что SELECT и INSERT будут выполняться на каждом шарде в базовую таблицу распределённого движка и из неё на каждом узле.
Как и ожидалось, это снижает производительность вставки втрое.

Дополнительная настройка

Отключение дедупликации

Операции вставки иногда могут завершаться ошибкой, например из-за тайм-аутов. В таких случаях данные могли как успешно записаться, так и не записаться. Чтобы клиент мог безопасно повторить попытку вставки, в распределённых развёртываниях, таких как ClickHouse Cloud, ClickHouse по умолчанию пытается определить, были ли данные уже успешно вставлены. Если вставленные данные помечаются как дубликат, ClickHouse не вставляет их в целевую таблицу. Однако пользователь всё равно получит статус успешного выполнения операции — как если бы данные были вставлены обычным образом. Хотя такое поведение, создающее дополнительную нагрузку при вставке, оправдано при загрузке данных с клиента или пакетами, оно может быть излишним при выполнении INSERT INTO SELECT из объектного хранилища. Если отключить эту функциональность во время вставки, можно повысить производительность, как показано ниже:

Оптимизация при вставке

В ClickHouse настройка optimize_on_insert определяет, будут ли части данных сливаться в процессе вставки. Когда она включена (optimize_on_insert = 1 по умолчанию), небольшие части сливаются в более крупные по мере вставки, что повышает производительность запросов за счёт сокращения числа частей, которые нужно читать. Однако такое слияние создаёт дополнительную нагрузку на процесс вставки и может замедлить вставки с высокой пропускной способностью. Отключение этой настройки (optimize_on_insert = 0) отключает слияние во время вставки, позволяя записывать данные быстрее, особенно при частых небольших вставках. Процесс слияния переносится в фоновый режим, что улучшает производительность вставки, но временно увеличивает количество небольших частей, из-за чего запросы могут выполняться медленнее, пока фоновое слияние не завершится. Эта настройка особенно полезна, когда в приоритете скорость вставки, а фоновый процесс слияния может позже эффективно выполнить оптимизацию. Как показано ниже, отключение этой настройки может повысить пропускную способность вставки:

Прочие замечания

  • При нехватке памяти, если вы вставляете данные в S3, попробуйте уменьшить max_insert_delayed_streams_for_parallel_write.
Последнее изменение 23 июля 2026 г.