Новая настройка allow_asynchronous_read_from_io_pool_for_merge_tree позволяет увеличить число потоков чтения (потоков) по сравнению с числом потоков в остальной части конвейера выполнения запроса.
Обычно настройка max_threads определяет количество потоков для параллельного чтения и параллельной обработки запросов:
Данные читаются «по порядку», столбец за столбцом, с диска.
Асинхронное чтение данных
Новая настройка allow_asynchronous_read_from_io_pool_for_merge_tree позволяет увеличить число потоков чтения (потоков) по сравнению с числом потоков в остальной части конвейера выполнения запроса, чтобы ускорить холодные запросы в сервисах ClickHouse Cloud с небольшим числом CPU и повысить производительность запросов, ограниченных I/O.
Когда настройка включена, количество потоков чтения управляется настройкой max_streams_for_merge_tree_reading:
Данные читаются асинхронно, параллельно из разных столбцов.
Обратите внимание, что для настройки соотношения между числом потоков чтения (потоков) и числом потоков в остальной части конвейера выполнения запроса также существует настройка max_streams_to_max_threads_ratio. Однако в бенчмарках она оказалась не такой полезной, как настройка max_streams_for_merge_tree_reading
Что насчёт optimize_read_in_order?
Благодаря оптимизации optimize_read_in_order ClickHouse может избежать повторной сортировки данных в памяти, если порядок сортировки в запросах соответствует физическому порядку данных на диске, но для этого данные нужно читать по порядку (в отличие от асинхронного чтения):
optimize_read_in_order имеет приоритет перед асинхронным чтением
Если ClickHouse определяет, что можно применить оптимизацию optimize_read_in_order, то настройка allow_asynchronous_read_from_io_pool_for_merge_tree будет проигнорирована / отключена.
Пример, демонстрирующий всё вышеперечисленное
SELECT getSetting('max_threads');
┌─getSetting('max_threads')─┐
│ 10 │
└───────────────────────────┘
- Проверьте конвейер выполнения запроса со стандартным числом потоков и для чтения, и для обработки данных
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid;
┌─explain──────────────────────┐
│ (Expression) │
│ ExpressionTransform × 10 │
│ (ReadFromMergeTree) │
│ MergeTreeThread × 10 0 → 1 │
└──────────────────────────────┘
- Проверьте конвейер запроса с 60 потоками асинхронного чтения и числом потоков по умолчанию для остальной части конвейера выполнения запроса
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid
SETTINGS
allow_asynchronous_read_from_io_pool_for_merge_tree = 1,
max_streams_for_merge_tree_reading = 60;
┌─explain────────────────────────┐
│ (Expression) │
│ ExpressionTransform × 10 │
│ (ReadFromMergeTree) │
│ Resize 60 → 10 │
│ MergeTreeThread × 60 0 → 1 │
└────────────────────────────────┘
- Проверьте конвейер выполнения запроса с 20 потоками для чтения и обработки данных
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid
SETTINGS
max_threads = 20;
┌─explain──────────────────────┐
│ (Expression) │
│ ExpressionTransform × 20 │
│ (ReadFromMergeTree) │
│ MergeTreeThread × 20 0 → 1 │
└──────────────────────────────┘
- Проверьте конвейер запроса: 60 потоков для асинхронного чтения и 20 — для остальной части конвейера выполнения запроса
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid
SETTINGS
max_threads = 20,
allow_asynchronous_read_from_io_pool_for_merge_tree = 1,
max_streams_for_merge_tree_reading = 60;
┌─explain────────────────────────┐
│ (Expression) │
│ ExpressionTransform × 20 │
│ (ReadFromMergeTree) │
│ Resize 60 → 20 │
│ MergeTreeThread × 60 0 → 1 │
└────────────────────────────────┘
- Проверьте конвейер запроса с 60 асинхронными потоками чтения и 20 потоками для остальной части выполнения запроса,
когда можно применить оптимизацию
optimize_read_in_order optimization
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid
ORDER BY postcode1, postcode2
SETTINGS
max_threads = 20,
allow_asynchronous_read_from_io_pool_for_merge_tree= 1,
max_streams_for_merge_tree_reading= 60;
┌─explain───────────────────────────┐
│ (Expression) │
│ ExpressionTransform │
│ (Sorting) │
│ MergingSortedTransform 20 → 1 │
│ (Expression) │
│ ExpressionTransform × 20 │
│ (ReadFromMergeTree) │
│ MergeTreeInOrder × 20 0 → 1 │
└───────────────────────────────────┘
-- обратите внимание, что это эквивалентно отключению allow_asynchronous_read_from_io_pool_for_merge_tree
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid
ORDER BY postcode1, postcode2
SETTINGS
max_threads = 20,
allow_asynchronous_read_from_io_pool_for_merge_tree = 0,
max_streams_for_merge_tree_reading = 0;
┌─explain───────────────────────────┐
│ (Expression) │
│ ExpressionTransform │
│ (Sorting) │
│ MergingSortedTransform 20 → 1 │
│ (Expression) │
│ ExpressionTransform × 20 │
│ (ReadFromMergeTree) │
│ MergeTreeInOrder × 20 0 → 1 │
└───────────────────────────────────┘
-- обратите внимание, что можно принудительно включить allow_asynchronous_read_from_io_pool_for_merge_tree, отключив optimize_read_in_order
EXPLAIN PIPELINE
SELECT *
FROM uk_price_paid
ORDER BY
postcode1 ASC,
postcode2 ASC
SETTINGS
max_threads = 20,
allow_asynchronous_read_from_io_pool_for_merge_tree = 1,
max_streams_for_merge_tree_reading = 60,
optimize_read_in_order = 0;
┌─explain──────────────────────────────┐
│ (Expression) │
│ ExpressionTransform │
│ (Sorting) │
│ MergingSortedTransform 20 → 1 │
│ MergeSortingTransform × 20 │
│ (Expression) │
│ ExpressionTransform × 20 │
│ (ReadFromMergeTree) │
│ Resize 60 → 20 │
│ MergeTreeThread × 60 0 → 1 │
└──────────────────────────────────────┘
Последнее изменение 10 июня 2026 г.