通常,max_threads 设置控制并行读取线程和并行查询处理线程的数量
数据按顺序从磁盘读取,一列一列。
异步数据读取
新的设置 allow_asynchronous_read_from_io_pool_for_merge_tree 允许读取线程(流)的数量高于查询执行管道中其余线程的数量,以加快 ClickHouse 云服务上的冷查询速度,并提高 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
设置将被忽略/禁用。
演示以上所有内容的示例
创建并加载 英国房产价格支付表
检查 max_threads 的设置值(默认情况下,ClickHouse 在执行查询的节点上看到的 CPU 内核数量
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 │
└────────────────────────────────┘
- 当可以应用
optimize_read_in_order
优化时,检查查询管道,其中使用60个异步读取线程和20个线程用于查询执行管道的其余部分。
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 │
└───────────────────────────────────┘
-- note that this is equivalent to disabling 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 │
└───────────────────────────────────┘
-- note that you can enforce allow_asynchronous_read_from_io_pool_for_merge_tree by disabling 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 │
└──────────────────────────────────────┘