跳至主要内容

同步数据读取

·阅读时长 4 分钟

通常,max_threads 设置控制并行读取线程和并行查询处理线程的数量

Untitled scene

数据按顺序从磁盘读取,一列一列。

异步数据读取

新的设置 allow_asynchronous_read_from_io_pool_for_merge_tree 允许读取线程(流)的数量高于查询执行管道中其余线程的数量,以加快 ClickHouse 云服务上的冷查询速度,并提高 I/O 绑定查询的性能。启用此设置后,读取线程的数量由 max_streams_for_merge_tree_reading 设置控制

Untitled scene

数据异步读取,并行地从不同的列读取。

请注意,还有 max_streams_to_max_threads_ratio 设置用于配置读取线程(流)的数量与查询执行管道中其余线程的数量之间的比率。但是,在基准测试中,它不像 max_streams_for_merge_tree_reading 设置那样有效

optimize_read_in_order 怎么样?

使用 optimize_read_in_order 优化,ClickHouse 可以跳过内存中的数据重新排序,如果查询排序顺序反映了磁盘上数据的物理顺序,但这需要按顺序读取数据(与异步读取相反)

Untitled scene

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 │
└──────────────────────────────────────┘