加速您的ClickHouse查询

【clickhouse踩坑记录】ClickHouse查询性能优化(入门级) 背景 用了一年多的ClickHouse,但好像都没系统地去学一遍,趁着最近有点时间,相对全面地去看了一圈ClickHouse的内容。发现ClickHouse虽然性能查询本身快,但如果使用不恰当,性能会被降一个级别。下面主要简单介绍一下,ClickHouse的查询可以从哪些方面做优化。可重点关注标题加粗部分!! 优化方法 表级别优化 填充有空值的字段 对于一些表字段,若存在空值,则可以考虑使用无业务场景意义的字符进行填充。因为ClickHouse对于空值,在底层存储是用了单独的文件存储。相对于没有空值的情 阅读详情
AI摘要

本文介绍了加速ClickHouse查询的技巧。ClickHouse是优化实时分析的关系型数据库,可通过适当利用主索引、预先计算聚合、使用投影及增加查询处理并行性来加速查询。如创建不同主键表、利用投影自动同步和预计算聚合值,还可调整max_threads设置增加并行性。

图片

本文字数:12611;估计阅读时间:32 分钟

作者:Tom Schreiber

审校:庄晓东(魏庄)

本文在公众号【ClickHouseInc】首发

图片

引言

ClickHouse是一个优化了实时分析的关系型数据库管理系统,查询通常足够快,几乎不需要调整,但我们认为一毫秒都不应该浪费!在这篇文章中,我们将为您提供一些关于如何加速您的ClickHouse查询的技巧,并通过一些实际的例子,展示加速查询的方式。

快速查询处理的ClickHouse简介

ClickHouse中的表设计用于每秒接收数百万行的插入,并存储非常大的数据量。

ClickHouse的快速查询速度通常是通过适当利用表的(稀疏)主键索引来实现的,以极大地限制ClickHouse需要从磁盘读取的数据量,并防止在查询时重新排序数据,这也可以在使用LIMIT子句时启用短路实现。

ClickHouse主键索引的设计基于二分查找算法,该算法能够有效地(时间复杂度为O(log2 n))在排序数组中找到目标值的位置。

例如,考虑下面的排序数组,二分查找算法用于查找值42。该算法将目标值42与数组的中间元素进行比较。如果它们不相等,则排除目标不可能存在的半部分,并且在剩余的半部分上继续搜索,再次将中间元素与目标值进行比较,并重复此过程,直到找到目标值:

图片

使用表的主索引在ClickHouse表中查找行的方式与此相同。

表的行按照表的主键列(们)的顺序存储在磁盘上。

根据行的顺序,主索引(像上面的图表一样是排序的数组)存储来自表的第8192行的主键列值。

在下面的图表中,我们假设一个具有列“numbers”的表,它也是主键列:

图片

ClickHouse的主索引不是对个别行进行索引,而是对行的块(称为颗粒)进行索引。

有了这样的主索引,可以跳过数千兆字节甚至数百兆字节的数据,因此可以在(亚)秒内进行搜索。

下图显示了ClickHouse通常如何执行查询:

图片

第1步:将涉及表的主索引加载到主内存中。

第2步:通常通过对索引条目进行二分查找,ClickHouse选择可能包含与查询的WHERE子句匹配的行的块。

第3步:选定的行块并行流入ClickHouse查询引擎进行进一步处理,并将查询结果流向调用者。

ClickHouse中加速此查询执行工作流程的三个主要调整方向:

ClickHouse需要从磁盘流式传输到主内存的数据越少,查询的执行时间就越快。可以通过(1)适当利用主索引和(2)预先计算聚合来将从磁盘流式传输的数据量最小化。

数据的流式传输和实际处理可以通过(3)提高ClickHouse查询处理引擎内部使用的并行度来加快速度。

(1) 适当利用主索引

首先让我们看看如何确保充分利用主索引以确保最佳的查询性能。

利用索引从而最小化流入ClickHouse的数据量

我们以我们的英国房产价格支付教程中的表为例,该表有2764万行。此数据集可在我们的play.clickhouse.com环境中获得。

我们运行一个查询,列出了三个最高价格的伦敦郡:

SELECT
    county,
    price
FROM uk_price_paid
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3

┌─county─────────┬─────price─┐
│ GREATER LONDON │ 594300000 │
│ GREATER LONDON │ 569200000 │
│ GREATER LONDON │ 448500000 │
└────────────────┴───────────┘

3 rows in set. Elapsed: 0.044 sec. Processed 27.64 million rows, 44.21 MB (634.60 million rows/s., 1.01 GB/s.)

ClickHouse正在进行全表扫描!

因为表的主索引无法为查询充分利用。

我们检查表的主键:

SHOW CREATE TABLE uk_price_paid

CREATE TABLE default.uk_price_paid
(
    `price` UInt32,
    `date` Date,
    `postcode1` LowCardinality(String),
    `postcode2` LowCardinality(String),
    `type` Enum8('other' = 0, 'terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4),
    `is_new` UInt8,
    `duration` Enum8('unknown' = 0, 'freehold' = 1, 'leasehold' = 2),
    `addr1` String,
    `addr2` String,
    `street` LowCardinality(String),
    `locality` LowCardinality(String),
    `town` LowCardinality(String),
    `district` LowCardinality(String),
    `county` LowCardinality(String),
    `category` UInt8
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/fb100991-4cae-4a92-995a-1ca11416879e/{shard}', '{replica}')
ORDER BY (postcode1, postcode2, addr1, addr2)
SETTINGS index_granularity = 8192

1 row in set. Elapsed: 0.001 sec.

表的ORDER BY子句确定数据在磁盘上的排序方式和主索引条目。ORDER BY中的列为postcode1,postcode2,addr1和addr2。

请注意,如果没有明确定义主键,ClickHouse将使用排序键(由ORDER BY子句定义)作为主键,即通过PRIMARY KEY子句。

这对于具有town = 'LONDON'谓词的查询没有帮助。

如果我们想要显著加速我们的示例查询以过滤具有特定城镇的行,则需要使用为该查询优化的主索引。

其中一种选择是创建具有基于不同主键的不同行顺序的第二个表。

由于表只能在磁盘上有一个物理顺序,我们需要将表数据复制到另一个表中。

我们创建了一个与原始表具有相同架构但具有不同主键的第二个表,并在表之间复制数据:

CREATE TABLE uk_price_paid_oby_town_price
(
    price UInt32,
    date Date,
    postcode1 LowCardinality(String),
    postcode2 LowCardinality(String),
    type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0),
    is_new UInt8,
    duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0),
    addr1 String,
    addr2 String,
    street LowCardinality(String),
    locality LowCardinality(String),
    town LowCardinality(String),
    district LowCardinality(String),
    county LowCardinality(String),
    category UInt8
)
ENGINE = MergeTree
ORDER BY (town, price);

INSERT INTO uk_price_paid_oby_town_price
SELECT * FROM uk_price_paid;

0 rows in set. Elapsed: 13.033 sec. Processed 52.50 million rows, 2.42 GB (4.03 million rows/s., 185.58 MB/s.)

我们在第二个表上运行查询:

SELECT
    county,
    price
FROM uk_price_paid_oby_town_price
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3

┌─county─────────┬─────price─┐
│ GREATER LONDON │ 594300000 │
│ GREATER LONDON │ 569200000 │
│ GREATER LONDON │ 448500000 │
└────────────────┴───────────┘

3 rows in set. Elapsed: 0.005 sec. Processed 81.92 thousand rows, 493.76 KB (15.08 million rows/s., 90.87 MB/s.)

多了。

利用索引来防止重新排序并启用短路

在我们的上一个示例中,ClickHouse不仅从磁盘上流出了更少的数据,还应用了额外的优化。

查询是:

  • 过滤town = ‘London’的行

  • 按价格降序排序匹配的行

  • 获取前3行

为此,通常,ClickHouse:

  • 使用主索引选择可能包含‘London’行的块,并从磁盘上流出这些行

  • 按价格对这些行进行排序

  • 将前3行作为结果流向调用者

但是,因为磁盘上的‘London’行已经按价格排序存储(请参阅表DDL的ORDER BY子句),ClickHouse可以直接跳过在主内存中重新排序。

而且ClickHouse可以进行短路。ClickHouse所需要做的就是以相反的顺序从磁盘上流出所选块的行,并且一旦流出了三个匹配(town = ‘London’)行,查询就完成了。

这正是在这种情况下optimize_read_in_order优化所做的 - 防止行重新排序并启用短路。

这个优化默认启用,当我们通过EXPLAIN检查查询的逻辑查询计划时,我们可以看到计划底部的ReadType:InReverseOrder:

EXPLAIN actions = 1
SELECT
    county,
    price
FROM uk_price_paid_oby_town_price
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3


 Expression (Projection)                                                                                        
 Actions: INPUT :: 0 -> price UInt32 : 0                                                                        
          INPUT :: 1 -> county LowCardinality(String) : 1                                                       
 Positions: 1 0                                                                                                 
   Limit (preliminary LIMIT (without OFFSET))                                                                   
   Limit 3                                                                                                      
   Offset 0                                                                                                     
     Sorting (Sorting for ORDER BY)                                                                             
     Prefix sort description: price DESC                                                                        
     Result sort description: price DESC                                                                        
     Limit 3                                                                                                    
       Expression (Before ORDER BY)                                                                             
       Actions: INPUT :: 0 -> price UInt32 : 0                                                                  
                INPUT :: 1 -> county LowCardinality(String) : 1                                                 
       Positions: 0 1                                                                                           
         Filter (WHERE)                                                                                         
         Filter column: equals(town, 'LONDON') (removed)                                                        
         Actions: INPUT :: 0 -> price UInt32 : 0                                                                
                  INPUT : 1 -> town LowCardinality(String) : 1                                                  
                  INPUT :: 2 -> county LowCardinality(String) : 2                                               
                  COLUMN Const(String) -> 'LONDON' String : 3                                                   
                  FUNCTION equals(town :: 1, 'LONDON' :: 3) -> equals(town, 'LONDON') LowCardinality(UInt8) : 4 
         Positions: 0 2 4                                                                                       
           ReadFromMergeTree (default.uk_price_paid_oby_town_price)                                                           
           ReadType: InReverseOrder                                                                             
           Parts: 6                                                                                             
           Granules: 267                                                                                        

27 rows in set. Elapsed: 0.002 sec.

optimize_read_in_order设置可以通过查询的SETTINGS子句禁用。这将导致ClickHouse从磁盘上流出217万行而不是8192行(仍然优于全表扫描)。以下图表显示了查询处理步骤的差异:

图片

使用具有不同行顺序的第二个表的一个剩余问题是保持表的同步。在下面,我们将讨论这个问题的一个方便的解决方案。

(2) 预先计算聚合

我们执行一个聚合查询,列出了英国的县,按平均支付价格排序:

SELECT
    county,
    avg(price)
FROM uk_price_paid
GROUP BY county
ORDER BY avg(price) DESC
LIMIT 3

┌─county──────────────────────────────┬─────────avg(price)─┐
│ WINDSOR AND MAIDENHEAD              │ 383843.17329304793 │
│ BOURNEMOUTH, CHRISTCHURCH AND POOLE │  383478.9135281004 │
│ GREATER LONDON                      │  376911.4824869095 │
└─────────────────────────────────────┴────────────────────┘

3 rows in set. Elapsed: 0.020 sec. Processed 26.25 million rows, 132.57 MB (1.33 billion rows/s., 6.69 GB/s.)

在这种情况下,ClickHouse 正在进行全表扫描,因为查询聚合了所有现有的表行。因此,无法使用主索引来减少从磁盘流入的数据量。

然而,如果我们可以为所有现有的 130 个英国县预先计算聚合值并在原始表数据更改时更新该单独的表,就可以大大减少从磁盘流入的数据量(通过牺牲额外的磁盘空间)。

以下图表现了这个想法:

图片

ClickHouse 有一个方便的新的即插即用功能来实现这个想法:投影Projections!

使用投影(Projections)来进行 (1) 和 (2)

ClickHouse 表可以有 (多个) 投影。

投影是一个额外的(隐藏的)表,它与原始表自动保持同步。投影可以具有不同的行顺序(因此具有不同的主索引)和自动和增量地预先计算聚合值。

当一个查询针对原始表时,ClickHouse 会自动选择(通过对主键进行抽样)一个可以生成相同正确结果的表,但需要读取的数据量最少。我们在这里展示了这个概念:

图片

投影与材料化视图有些类似,后者也允许您进行增量聚合和多个行顺序。但与材料化视图不同,投影是原子更新的,并且通过在查询时自动选择最佳版本来保持与主表一致。

对于原始示例表 uk_price_paid,我们将创建(并填充)两个投影。

为了在我们的游乐场中保持事物整洁和简单,我们首先将表 uk_price_paid 复制为 uk_price_paid_with_projections:

CREATE TABLE uk_price_paid_with_projections AS uk_price_paid;
INSERT INTO uk_price_paid_with_projections SELECT * FROM uk_price_paid;

0 rows in set. Elapsed: 4.410 sec. Processed 52.50 million rows, 2.42 GB (11.90 million rows/s., 548.46 MB/s.)

我们创建和填充投影 prj_oby_town_price - 一个额外的(隐藏的)表,具有主索引,按城镇和价格排序,以优化查询,该查询列出了特定城镇的县,用于最高的支付价格:

ALTER TABLE uk_price_paid_with_projections
    ADD PROJECTION prj_oby_town_price
    (
        SELECT
            *
        ORDER BY
          town, price
    );

ALTER TABLE uk_price_paid_with_projections
    MATERIALIZE PROJECTION prj_oby_town_price SETTINGS mutations_sync = 1;
    
0 rows in set. Elapsed: 6.028 sec.

我们创建和填充投影 prj_gby_county - 一个额外的(隐藏的)表,它逐渐预先计算了所有现有的 130 个英国县的 avg(price) 聚合值:

ALTER TABLE uk_price_paid_with_projections
    ADD PROJECTION prj_gby_county
    (
        SELECT
            county,
            avg(price)
        GROUP BY
           county
    );

ALTER TABLE uk_price_paid_with_projections
    MATERIALIZE PROJECTION prj_gby_county SETTINGS mutations_sync = 1;

0 rows in set. Elapsed: 0.123 sec.

请注意,如果在投影中使用了 GROUP BY 子句(如上面的 prj_gby_county 中),则(隐藏的)表的底层存储引擎将变为 AggregatingMergeTree,并且所有聚合函数都将转换为 AggregateFunction。这确保了适当的增量数据聚合。

此外,请注意强制同步执行的 SETTINGS 子句。

这是主表 uk_price_paid_with_projections 及其两个投影的可视化:

图片

如果我们现在运行该查询,该查询列出了伦敦的县,以最高的支付价格为准,我们会看到性能上的巨大差异:

SELECT
    county,
    price
FROM uk_price_paid_with_projections
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3

┌─county─────────┬─────price─┐
│ GREATER LONDON │ 594300000 │
│ GREATER LONDON │ 569200000 │
│ GREATER LONDON │ 448500000 │
└────────────────┴───────────┘

3 rows in set. Elapsed: 0.026 sec. Processed 2.17 million rows, 13.03 MB (83.14 million rows/s., 499.14 MB/s.)

同样,对于列出英国的三个最高平均支付价格的县的查询:

SELECT
    county,
    avg(price)
FROM uk_price_paid_with_projections
GROUP BY county
ORDER BY avg(price) DESC
LIMIT 3

┌─county──────────────────────────────┬─────────avg(price)─┐
│ WINDSOR AND MAIDENHEAD              │  398334.9180566017 │
│ GREATER LONDON                      │  396401.2740568222 │
│ BOURNEMOUTH, CHRISTCHURCH AND POOLE │ 387441.28323942184 │
└─────────────────────────────────────┴────────────────────┘

3 rows in set. Elapsed: 0.007 sec.

请注意,两个查询都针对原始表,两个查询在创建两个投影之前都会导致全表扫描(所有 27.64 百万行都会从磁盘流入)。

此外,请注意,列出伦敦的县的最高支付价格的查询正在流式传输 217 万行。当我们直接使用一个为此查询优化的第二个表时,只有 8.192 万行从磁盘流入。

差异的原因是目前上面提到的 optimize_read_in_order 优化不支持投影。

为了查看 ClickHouse 是否自动使用了上面两个查询的两个投影,我们检查 system.query_log 表(请参见下面的投影列):

SELECT
    tables,
    query,
    query_duration_ms::String ||  ' ms' AS query_duration,
    formatReadableQuantity(read_rows) AS read_rows,
    projections
FROM clusterAllReplicas(default, system.query_log)
WHERE (type = 'QueryFinish') AND (tables = ['default.uk_price_paid_with_projections'])
ORDER BY initial_query_start_time DESC
LIMIT 2
FORMAT Vertical

Row 1:
──────
tables:         ['default.uk_price_paid_with_projections']
query:          SELECT
                  county,
                  avg(price)
                FROM uk_price_paid
                GROUP BY county
                ORDER BY avg(price) DESC
                LIMIT 3
query_duration: 6 ms
read_rows:      597.00
projections:    ['default.uk_price_paid.prj_gby_county']

Row 2:
──────
tables:         ['default.uk_price_paid_with_projections']
query:          SELECT
                  county,
                  price
                FROM uk_price_paid
                WHERE town = 'LONDON'
                ORDER BY price DESC
                LIMIT 3
query_duration: 25 ms
read_rows:      2.17 million
projections:    ['default.prj_oby_town_price']

增加查询处理并行性

大多数分析查询都有一个过滤器、聚合器和排序阶段。每个阶段都可以独立并行化,并且默认情况下将使用与 CPU 核心数相同数量的线程,从而充分利用查询的所有机器资源(因此,在 ClickHouse 中,扩大规模优于扩展)。

发送到 ClickHouse 的查询会转换为一个称为查询管道的物理查询计划,该管道由在从磁盘流入的数据上执行的查询处理阶段组成。

如第一段所述,为了执行查询,ClickHouse 首先使用主索引来选择可能包含与查询的 WHERE 子句匹配的行的块。

选定的行块被分成 n 个单独的数据范围。

n 取决于 max_threads 设置,该设置默认设置为 ClickHouse 在运行的机器上看到的 CPU 核心数。

同时,每个数据范围的一个线程将以块方式流式传输从其范围读取的行。大多数查询处理阶段都以流式方式由 n 个线程并行执行。

我们以具有 4 个 CPU 核心的 ClickHouse 节点为例进行可视化:

图片

通过增加查询的 max_threads 设置,可以增加数据处理的并行性。

我们可以通过 EXPLAIN 来检查查询的查询管道:

EXPLAIN PIPELINE
SELECT
    county,
    price
FROM uk_price_paid
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3

┌─explain─────────────────────────────────┐
│ (Expression)                            │
│ ExpressionTransform                     │
│   (Limit)                               │
│   Limit                                 │
│     (Sorting)                           │
│     MergingSortedTransform 4 → 1        │
│       MergeSortingTransform × 4         │
│         LimitsCheckingTransform × 4     │
│           PartialSortingTransform × 4   │
│             (Expression)                │
│             ExpressionTransform × 4     │
│               (ReadFromMergeTree)       │
│               MergeTreeThread × 4 0 → 1 │
└─────────────────────────────────────────┘

13 rows in set. Elapsed: 0.002 sec.

计划可以从底向上阅读,我们可以看到有 4 个并行线程用于从磁盘读取/流式传输选定的行块,并且查询管道中的大多数查询处理阶段都由 4 个线程并行执行。

4 个线程,因为 EXPLAIN 查询在一个具有 4 个 CPU 核心的 ClickHouse 节点上运行,因此 max_threads 默认设置为 4:

SELECT *
FROM system.settings
WHERE name = 'max_threads'
FORMAT Vertical

Row 1:
──────
name:        max_threads
value:       4
changed:     0
description: The maximum number of threads to execute the request. By default, it is determined automatically.
min:         ᴺᵁᴸᴸ
max:         ᴺᵁᴸᴸ
readonly:    0
type:        MaxThreads

1 row in set. Elapsed: 0.009 sec.

我们再次检查相同查询的查询管道,该查询现在具有增加 max_threads 设置为 20 的 SETTINGS 子句:

EXPLAIN PIPELINE
SELECT
    county,
    price
FROM uk_price_paid
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3
SETTINGS max_threads = 20

┌─explain──────────────────────────────────┐
│ (Expression)                             │
│ ExpressionTransform                      │
│   (Limit)                                │
│   Limit                                  │
│     (Sorting)                            │
│     MergingSortedTransform 20 → 1        │
│       MergeSortingTransform × 20         │
│         LimitsCheckingTransform × 20     │
│           PartialSortingTransform × 20   │
│             (Expression)                 │
│             ExpressionTransform × 20     │
│               (ReadFromMergeTree)        │
│               MergeTreeThread × 20 0 → 1 │
└──────────────────────────────────────────┘

13 rows in set. Elapsed: 0.003 sec.

现在有 20 个并行线程用于从磁盘读取/流式传输选定的行块,并且查询管道中的大多数查询处理阶段都由 20 个线程并行执行。

我们使用 4 个线程运行查询(ClickHouse 玩场的默认 max_threads 设置):

SELECT
    county,
    price
FROM uk_price_paid
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3

┌─county─────────┬─────price─┐
│ GREATER LONDON │ 594300000 │
│ GREATER LONDON │ 569200000 │
│ GREATER LONDON │ 448500000 │
└────────────────┴───────────┘

3 rows in set. Elapsed: 0.070 sec. Processed 27.64 million rows, 40.53 MB (393.86 million rows/s., 577.50 MB/s.)

我们使用 20 个线程运行查询:

SELECT
    county,
    price
FROM uk_price_paid
WHERE town = 'LONDON'
ORDER BY price DESC
LIMIT 3
SETTINGS max_threads = 20

┌─county─────────┬─────price─┐
│ GREATER LONDON │ 594300000 │
│ GREATER LONDON │ 569200000 │
│ GREATER LONDON │ 448500000 │
└────────────────┴───────────┘

3 rows in set. Elapsed: 0.036 sec. Processed 27.64 million rows, 40.00 MB (765.42 million rows/s., 1.11 GB/s.)

使用 20 个线程,查询速度大约加快了一倍,但请注意,这会增加查询执行消耗的峰值内存量,因为会有更多的数据并行流入 ClickHouse。

我们通过检查 system.query_log 表来检查两个查询运行的内存消耗:

SELECT
    query,
    query_duration_ms::String || ' ms' as query_duration,
    formatReadableSize(memory_usage) as memory_usage,
    formatReadableQuantity(read_rows) AS read_rows,
    formatReadableSize(read_bytes) as read_data
FROM clusterAllReplicas(default, system.query_log)
WHERE type = 'QueryFinish' AND tables = ['default.uk_price_paid']
ORDER BY initial_query_start_time DESC
LIMIT 2
FORMAT Vertical

Row 1:
──────
query:          SELECT
                  county,
                  price
                FROM uk_price_paid
                WHERE town = 'LONDON'
                ORDER BY price DESC
                LIMIT 3
                SETTINGS max_threads = 20
query_duration: 35 ms
memory_usage:   49.49 MiB
read_rows:      27.64 million
read_data:      38.15 MiB

Row 2:
──────
query:          SELECT
                  county,
                  price
                FROM uk_price_paid
                WHERE town = 'LONDON'
                ORDER BY price DESC
                LIMIT 3
query_duration: 69 ms
memory_usage:   31.01 MiB
read_rows:      27.64 million
read_data:      38.65 MiB

2 rows in set. Elapsed: 0.026 sec. Processed 64.00 thousand rows, 5.98 MB (2.46 million rows/s., 230.17 MB/s.)

使用 20 个线程,查询消耗的峰值主内存约增加了 40%,而使用 4 个线程的相同查询运行。

请注意,对于高 max_threads 设置,资源争用和上下文切换可能会成为瓶颈,因此增加 max_threads 设置不会线性扩展。

总结

ClickHouse 查询处理架构针对实时分析进行了优化,并且具有使查询处理快速的默认设置。

您可以通过应用上述描述的技术来优化特定查询的性能:

  • 选择包括您过滤的字段的行顺序/主键

  • 为多个行顺序和增量聚合添加投影

  • 增加查询处理并行性的级别

这将最小化从磁盘流入查询处理引擎的数据量,并加快数据的流式传输和处理。

图片

​​联系我们

手机号:13910395701

邮箱:Tracy.Wang@clickhouse.com

满足您所有的在线分析列式数据库管理需求

Clickhouse性能优化 阅读详情

相关推荐

【场景实战】 ClickHouse 查询缓慢的问题分析排查

必需] 从开始:找到慢查询,记录其read_rowsread_bytes。[必需] 检查 SQL 的 WHERE 条件:是否有效利用了主键?是否避免了函数和低效操作(LIKE, IN)?[推荐] 使用EXPLAIN查看执行计划和可以帮助理解查询如何利用主键和分区。[检查] 表结构:主键/排序键设置是否合理?分区数量是否健康?[监控] 系统资源:在查询运行时,快速查看 CPU、内存、磁盘 I/O 的使用情况,定位硬件瓶颈。[高级] 考虑索引:是否为频繁过滤的非主键列创建了合适的跳数索引?

wamp0001的博客 1787

大数据场景下clickhouse查询时长优化sop

3.join查询 1)左大右小(在join的时候右表会被全部加载到内存中和左表比较) 2)谓词下推 3)避免多表join 4)global join (global关键字可以使右表只在接收查询请求的那个节点查询一次,将其分发到其他节点上,如果不加的话每个节点都会请求一次,造成很大的开销)为了提高查询性能,需要针对实际的查询场景进行索引的设计,尽量避免使用不必要的索引,以减少数据写入和查询时的开销。ClickHouse的优化需要结合实际的数据特点和查询场景,从多个方面进行综合优化,以提高系统的性能和可靠性。

xiaocaij_icai的博客 3100

ClickHouse压缩机制:从存储优化到查询加速的实战指南

数据压缩技术在现代数据库系统中扮演着关键角色,传统认知中它主要用于节省存储空间。然而在列式存储架构下,压缩技术通过减少I/O带宽占用、提升CPU向量化计算效率、增加内存缓存命中率等方式,实现了查询性能的显著提升。以ClickHouse为代表的OLAP数据库将压缩作为核心计算加速策略,支持LZ4、ZSTD、Gorilla等多种编解码器,针对时间序列、用户行为等不同数据类型需要采用差异化压缩方案。合理的压缩策略配合分区、预聚合等技术,能在金融分析、物联网监控等大数据场景中实现3倍以上的查询加速效果,同时降低60

weixin_30307921的博客 537

clickhouse

什么是ClickHouse ClickHouse是俄罗斯的Yandex于2016年开源的⼀个⽤于联机分析(OLAP:Online Analytical Processing)的列式数据 库管理系统(DBMS:Database Management System),简称CH , 主要⽤于在线分析处理查询(OLAP),能够使⽤ SQL查询实时⽣成分析数据报告。 ClickHouse是⼀个完全的列式数据库管理系统,允许在运⾏时创建表和数据库,加载数据和运⾏查询,⽽⽆需重 新配置和重新启动服务器,⽀持线性扩展,

leezsj的博客 2686

实战攻略 | ClickHouse优化之FINAL查询加速

ClickHouse:介绍两种方法来做final查询的优化

边逛边看边学习 2505

ClickHouse 内核分析--MergeTree 的存储结构和查询加速

ClickHouse 内核分析–MergeTree 的存储结构和查询 加速 ClickHouse 是最近比较火的一款开源列式存储分析型数据库,它最核心的特点就是极致存储压缩率和查询 性能,本人最近正在学习 ClickHouse 这款产品中。从我个人的视角来看存储是决定一款数据库核心竞争力、 适用场景的关键所在,所以接下来我会陆续推出一系列文章来分析 ClickHouse 中最重要的 MergeTree 存储 内核。本文主旨在于介绍 MergeTree 的存储格式,并且彻底剖析 MergeTree 存储的极致

xiaozhaoshigedasb的博客 604

ClickHouse Projection 与物化索引:查询加速的轻量级方案

ClickHouse Projection 是介于物化视图和索引之间的轻量级查询加速方案。它通过"一份数据,多种组织"的方式,在不增加写入放大的前提下提供多种查询优化路径。落地时需关注存储开销、写入性能影响和一致性保障。建议从聚合 Projection 开始(存储开销小),逐步引入排序 Projection,单个表的 Projection 总数控制在 3 个以内。

guoyizhongxing的博客 4767

ClickHouse数据库的索引优化与查询加速技巧

随着企业数字化转型加速,秒级响应的实时报表、用户行为分析等需求激增。ClickHouse作为专为OLAP设计的数据库,理论上能处理亿级数据,但实际性能表现与索引设计强相关。本文聚焦索引优化这一核心环节,覆盖从索引原理到实战调优的全链路知识,帮助开发者解决“查询慢”的痛点。本文从“生活化场景”切入索引原理→拆解ClickHouse特有索引类型→通过代码实战演示优化过程→总结10条可落地的加速技巧→展望未来索引技术趋势,形成“原理-实践-经验”的完整知识闭环。稀疏索引。

AI天才研究院 1562

SigNoz性能优化:ClickHouse调优与查询加速技巧

你是否遇到过这样的情况:随着业务增长,SigNoz的查询响应时间越来越长,监控仪表盘加载缓慢,甚至在高负载时段出现超时?这往往是因为ClickHouse数据库没有经过适当优化导致的性能瓶颈。 作为一款基于ClickHouse构建的开源可观测性平台,SigNoz的性能很大程度上依赖于ClickHouse的配置和调优。本文将深入探讨如何通过ClickHouse调优来显著提升SigNoz的性能表现。 ...

gitblog_01056的博客 1096

ClickHouse物化视图:加速大数据聚合查询的利器

在大数据时代,数据量呈现爆炸式增长,企业和组织需要处理海量的数据以获取有价值的信息。聚合查询是数据分析中常见的操作,例如计算总和、平均值、计数等。然而,在处理大规模数据集时,聚合查询的执行时间往往很长,严重影响了数据分析的效率。ClickHouse作为一款高性能的列式数据库管理系统,能够快速处理大规模数据。而物化视图是ClickHouse中一种强大的工具,它可以预计算和存储聚合查询的结果,从而显著加速后续的查询操作。

AI云原生与云计算技术学院 376

k8s架构、工作流程、集群组件详解

Kubernetes(简称K8s,是因为 k 和 s 之间有八个字符)是一个开源的容器编排平台,用于管理云平台中多个主机上的容器化应用程序。它提供了一种机制,用于自动化部署、扩展和管理容器化应用程序的集群。Kubernetes的目标是让部署容器化应用程序变得简单高效。它提供了应用程序部署、规划、更新和维护的基本机制,同时具备强大的扩展性和可靠性。Kubernetes采用主从设备模型(Master-Slave架构),其中Master节点负责核心的调度、管理和运维任务,而Slave节点负责运行应用程序的容器。

qq_51545656的博客 4382

ClickHouse 物化视图与跳数索引:查询加速实践

ClickHouse 的查询加速,不是靠堆机器,而是靠把数据组织得"更利于被查"。物化视图把重复聚合固化下来,跳数索引把无关数据块挡在扫描之外。关键在"对症下药"。热点聚合才配物化视图,低基数列过滤才配跳数索引。脱离真实查询模式的设计,只会徒增存储与写入负担。当加速策略都落在实测瓶颈上,OLAP 查询的延迟与成本,才能同时回到健康区间。这正是工程化调优的精髓。

2401_83508463的博客 5443

动态对抗Zygisk-IL2CppDumper:Unity游戏安全新策略

本文深入探讨了对抗Zygisk-IL2CppDumper攻击的Unity游戏安全新策略。通过实时内存监控、动态混淆技术和异常行为检测体系,有效防止关键代码被动态提取。文章详细介绍了内存指纹系统、运行时混淆方案和五维特征模型等实用防御手段,帮助开发者提升游戏安全性。

weixin_29325955的博客 305

ClickHouse内核分析-MergeTree的存储结构和查询加速

作者:阿里巴巴数据库技术 链接:https://www.jianshu.com/p/16176d894678 来源:简书 引言ClickHouse是最近比较火的一款开源列式存储分析型数据...

huzechen的博客 849

python实现ECMS算法

ECMS(Equivalent Consumption Minimization Strategy)算法是一种用于混合动力汽车能量管理系统的优化策略。它通过计算等效油耗来平衡电池电量消耗和燃油消耗,从而优化整体能耗。以下是一个简单的Python实现,用于演示ECMS算法的基本思想。这个实现假设了一个简单的混合动力汽车模型,其中电池电量和燃油消耗是主要的优化目标。

weixin_45570158的博客 922

VFIO框架源码分析(二十一)- IOMMUFD 模式下的 DMA 映射机制

在虚拟化 I/O 的世界里,无论上层管理面(如对象模型、设备绑定)如何重构,数据面最核心的任务始终未变——DMA 映射(DMA Mapping)。即如何建立 Guest Physical Address (GPA) 到 Host Physical Address (HPA) 的映射关系,并将其填入 IOMMU 的硬件页表中,使得直通设备能够正确访问虚拟机内存。在 Legacy VFIO (Type1) 时代,这一职责由承担,它通过ioctl 操作 Container。

qq_36071928的博客 1007

探索ClickHouse——使用Projection加速查询

在测试Projection之前,我们需要先创建一张表,并导入大量数据。我们可以直接使用指令,从URL指向的文件中获取内容并导入表。但是担心网络不稳定,我们先将文件下载下来。

方亮的专栏 1495

ubuntu虚拟机搭建OP-TEE

在网上找了一些搭建OP-TEE的过程,模仿着进行搭建,结果有好多报错,为了方便自己以后重新搭建,所以将整个过程记录下来。

weixin_44213847的博客 998

ClickHouse跳数索引的设计与应用:Bloom Filter与MinMax在查询加速中的效果

ClickHouse的跳数索引是在排序键索引之外的"第二层过滤",通过MinMax、Set和Bloom Filter等轻量级统计摘要,在查询执行前过滤掉大量不相关的数据块。Bloom Filter是高基数列的最佳选择,Set索引适合低基数列,MinMax在有序列的范围过滤上效果显著。实践中建议为一个表创建2-4个跳数索引,覆盖最高频的过滤条件。记住一个核心原则:跳数索引的效果取决于数据在物理存储上的局部性——好的排序键设计能让跳数索引事半功倍。

guoyizhongxing的博客 4670

Unity 多线程编程笔记 _Task详解

士大夫

weixin_43405845的博客 4384

【搭建实战】全国天气预报看板搭建

不仅如此,码匠还一站式提供了企业内部系统常用的租户管理、细粒度的权限控制、审计日志等功能,让您快速搭建后台应用的同时,也为您的企业信息安全保驾护航。是一款国内研发的开发者友好的低代码平台,您无需了解React/Vue等框架的开发、部署等各种细节,就可以快速打通前后端,连接RESTAPI、MySQL、MongoDB等多种数据源,然后通过一套开箱即用的组件,轻松搭建功能完善的数据看板、数据洞察、Admin管理后台等多种应用。天气预报对我们的各项活动有很大的帮助,可以让我们合理安排自己的出行等活动。...

weixin_39545889的博客 426

ClickHouse深度解析:列式存储如何实现分析查询百倍加速

当传统关系型数据库在海量数据聚合分析面前显得力不从心时,OLAP专用引擎成为现代数据架构的关键一环。ClickHouse作为一款主打分析型查询的开源列式数据库,通过列式存储、稀疏索引和向量化执行等技术,将大数据量下的扫描聚合耗时从数十秒压缩至毫秒级。其高压缩比与极致查询性能,使其在日志分析、用户行为分析、监控指标存储及实时数仓等场景中备受青睐。理解ClickHouse的存储原理与适用边界,是合理选型OLAP组件、设计数据加速方案的基础,也是应对数据量持续增长下查询效率挑战的重要思路。

weixin_29574585的博客 299

Simulink开发项1000例实战专栏--实例64:基于Simulink构建一个储能系统模型

通过引入储能系统,太阳能电站能够实现在白天储存多余的能量,在夜晚释放能量,平滑负荷曲线,提高电网的稳定性和可靠性。本项目的目标是基于Simulink平台,构建一个完整的储能系统模型,并通过仿真验证其在电网调峰中的应用效果。通过引入储能系统,工业园区能够实现在负荷高峰期释放能量,在负荷低谷期储存能量,平滑负荷曲线,降低用电成本,提高电网的稳定性和可靠性。通过引入储能系统,风力发电场能够实现在负荷高峰期释放能量,在负荷低谷期储存能量,平滑负荷曲线,提高电网的稳定性和可靠性。

xiaoheshang_123的博客 514

ClickHouse内核分析 MergeTree的存储结构和查询加速

注:以下分析基于开源 v19.15.2.2-stable 版本进行 引言 ClickHouse是最近比较火的一款开源列式存储分析型数据库,它最核心的特点就是极致存储压缩率和查询性能,本人最近正在学习ClickHouse这款产品中。从我个人的视角来看存储是决定一款数据库核心竞争力、适用场景的关键所在,所以接下来我会陆续推出一系列文章来分析ClickHouse中最重要的MergeTree存储内核。本文主旨在于介绍MergeTree的存储格式,并且彻底剖析MergeTree存储的极致检索性能。 MergeT

breakout_alex的博客 680

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

HyperDX ClickHouse物化视图:5个实战技巧加速可观测性查询

HyperDX是一个开源的可观测性平台,能够统一会话回放、日志、指标、追踪和错误数据。作为ClickStack的核心组件,它利用ClickHouse的强大性能来处理海量遥测数据。在这篇文章中,我们将深入探讨如何通过**ClickHouse物化视图**来显著提升HyperDX查询性能的5个实战技巧。 ## 为什么物化视图对HyperDX至关重要? 在可观测性场景中,用户经常需要查询和分析大量的时

gitblog_00554的博客 641

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: 如何执行混合查询?
下一篇: 流式捕捉:ClickHouse的开箱即用CDC解决方案
ClickHouseDB
博客等级 码龄3年 1707粉丝 320原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值