跳至主要内容
跳至主要内容

主索引

正在寻找更高级的索引细节?

本页介绍 ClickHouse 的稀疏主索引,它的构建方式、工作原理以及如何帮助加速查询。

有关高级索引策略和更深入的技术细节,请参阅 主索引深度解析

ClickHouse 中稀疏主索引是如何工作的?


ClickHouse 中的稀疏主索引有助于有效地识别 颗粒 (granules)——行块——这些行块可能包含与表 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 列上的查询条件匹配的数据。在下一节中,我们将解释此索引如何从这些列中的值构建而来。

稀疏主索引创建

为了说明稀疏主索引的构建方式,我们使用 uk_price_paid_simple 表以及一些动画。

作为 提醒,在我们的 ① 示例表中,具有 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 (town, street) 的 ② 插入数据 ③ 存储在磁盘上,按 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 列值排序,并压缩在每个列的单独文件中



为了处理,每个列的数据 ④ 在逻辑上划分为颗粒——每个颗粒覆盖 8,192 行——这是 ClickHouse 数据处理机制所处理的最小单元。

这种 颗粒颗粒是未压缩块中的行批次。读取数据时,ClickHouse 访问颗粒而不是单个行,从而实现更快的分析工作负载数据处理。默认情况下,一个颗粒包含 8192 行。主索引包含每个颗粒的一个条目。 结构也是主索引是 稀疏 的原因:ClickHouse 不会索引每一行,而是仅存储来自每个 颗粒颗粒是未压缩块中的行批次。读取数据时,ClickHouse 访问颗粒而不是单个行,从而实现更快的分析工作负载数据处理。默认情况下,一个颗粒包含 8192 行。主索引包含每个颗粒的一个条目。 的一行(具体来说,第一行)的 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 值。这导致每个 颗粒颗粒是未压缩块中的行批次。读取数据时,ClickHouse 访问颗粒而不是单个行,从而实现更快的分析工作负载数据处理。默认情况下,一个颗粒包含 8192 行。主索引包含每个颗粒的一个条目。 产生一个索引条目。



由于其稀疏性,主索引足够小,可以完全放入内存中,从而能够快速过滤在 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 列上具有谓词的查询。在下一节中,我们将展示它如何帮助加速此类查询。

主索引使用

我们用另一个动画来描述稀疏主索引如何用于查询加速



① 示例查询包含对两个 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 列的谓词:town = 'LONDON' AND street = 'OXFORD STREET'

② 为了加速查询,ClickHouse 将表的索引加载到内存中。

③ 然后它扫描索引条目以识别可能包含与谓词匹配的行的颗粒——换句话说,哪些颗粒可以跳过。

④ 然后加载这些相关的颗粒并 处理 在内存中,以及查询所需的任何其他列的相应颗粒。

监控主索引

表中的每个 数据部分 都有自己的主索引。我们可以使用 mergeTreeIndex 表函数检查这些索引的内容。

以下查询列出了我们示例表中每个数据部分的主索引中的条目数

SELECT
    part_name,
    max(mark_number) AS entries
FROM mergeTreeIndex('uk', 'uk_price_paid_simple')
GROUP BY part_name;
   ┌─part_name─┬─entries─┐
1. │ all_2_2_0 │     914 │
2. │ all_1_1_0 │    1343 │
3. │ all_0_0_0 │    1349 │
   └───────────┴─────────┘

此查询显示了当前数据 部分磁盘上存储表数据的一个物理文件(或目录)。这与分区不同,分区是使用分区键创建的表的逻辑划分。 的主索引中的前 10 个条目。请注意,这些 部分磁盘上存储表数据的一个物理文件(或目录)。这与分区不同,分区是使用分区键创建的表的逻辑划分。 会在后台不断 合并 为更大的 部分磁盘上存储表数据的一个物理文件(或目录)。这与分区不同,分区是使用分区键创建的表的逻辑划分。

SELECT 
    mark_number + 1 AS entry,
    town,
    street
FROM mergeTreeIndex('uk', 'uk_price_paid_simple')
WHERE part_name = (SELECT any(part_name) FROM mergeTreeIndex('uk', 'uk_price_paid_simple')) 
ORDER BY mark_number ASC
LIMIT 10;
    ┌─entry─┬─town───────────┬─street───────────┐
 1. │     1 │ ABBOTS LANGLEY │ ABBEY DRIVE      │
 2. │     2 │ ABERDARE       │ RICHARDS TERRACE │
 3. │     3 │ ABERGELE       │ PEN Y CAE        │
 4. │     4 │ ABINGDON       │ CHAMBRAI CLOSE   │
 5. │     5 │ ABINGDON       │ THORNLEY CLOSE   │
 6. │     6 │ ACCRINGTON     │ MAY HILL CLOSE   │
 7. │     7 │ ADDLESTONE     │ HARE HILL        │
 8. │     8 │ ALDEBURGH      │ LINDEN ROAD      │
 9. │     9 │ ALDERSHOT      │ HIGH STREET      │
10. │    10 │ ALFRETON       │ ALMA STREET      │
    └───────┴────────────────┴──────────────────┘

最后,我们使用 EXPLAIN 子句查看所有数据 部分磁盘上存储表数据的一个物理文件(或目录)。这与分区不同,分区是使用分区键创建的表的逻辑划分。 的主索引如何用于跳过不可能包含与示例查询谓词匹配的行的颗粒。这些颗粒被排除在加载和处理之外

EXPLAIN indexes = 1
SELECT
    max(price)
FROM
    uk.uk_price_paid_simple
WHERE
    town = 'LONDON' AND street = 'OXFORD STREET';
    ┌─explain────────────────────────────────────────────────────────────────────────────────────────────────────┐
 1. │ Expression ((Project names + Projection))                                                                  │
 2. │   Aggregating                                                                                              │
 3. │     Expression (Before GROUP BY)                                                                           │
 4. │       Expression                                                                                           │
 5. │         ReadFromMergeTree (uk.uk_price_paid_simple)                                                        │
 6. │         Indexes:                                                                                           │
 7. │           PrimaryKey                                                                                       │
 8. │             Keys:                                                                                          │
 9. │               town                                                                                         │
10. │               street                                                                                       │
11. │             Condition: and((street in ['OXFORD STREET', 'OXFORD STREET']), (town in ['LONDON', 'LONDON'])) │
12. │             Parts: 3/3                                                                                     │
13. │             Granules: 3/3609                                                                               │
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

请注意,上述 EXPLAIN 输出的第 13 行显示,在所有数据 部分磁盘上存储表数据的一个物理文件(或目录)。这与分区不同,分区是使用分区键创建的表的逻辑划分。 中,只有 3 个颗粒中有 3,609 个颗粒被主索引分析选中进行处理。其余颗粒完全被跳过。

我们还可以通过简单地运行查询来观察大部分数据被跳过

SELECT max(price)
FROM uk.uk_price_paid_simple
WHERE (town = 'LONDON') AND (street = 'OXFORD STREET');
   ┌─max(price)─┐
1. │  263100000 │ -- 263.10 million
   └────────────┘

1 row in set. Elapsed: 0.010 sec. Processed 24.58 thousand rows, 159.04 KB (2.53 million rows/s., 16.35 MB/s.)
Peak memory usage: 13.00 MiB.

如上所示,示例表中大约 3000 万行中,只有大约 25,000 行被处理

SELECT count() FROM uk.uk_price_paid_simple;
   ┌──count()─┐
1. │ 29556244 │ -- 29.56 million
   └──────────┘

关键要点

  • 稀疏主索引 通过识别可能包含与 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 列上查询条件匹配的行的颗粒,帮助 ClickHouse 跳过不必要的数据。

  • 每个索引仅存储来自每个 颗粒颗粒是未压缩块中的行批次。读取数据时,ClickHouse 访问颗粒而不是单个行,从而实现更快的分析工作负载数据处理。默认情况下,一个颗粒包含 8192 行。主索引包含每个颗粒的一个条目。(默认情况下,一个 颗粒颗粒是未压缩块中的行批次。读取数据时,ClickHouse 访问颗粒而不是单个行,从而实现更快的分析工作负载数据处理。默认情况下,一个颗粒包含 8192 行。主索引包含每个颗粒的一个条目。 包含 8,192 行)的第一行的 主键在 ClickHouse 中,主键决定了数据在磁盘上的存储顺序,并用于构建稀疏索引以加速查询过滤。与传统数据库不同,ClickHouse 中的主键不强制唯一性——多行可以具有相同的主键值。 值,使其足够紧凑以适应内存。

  • 每个数据部分MergeTreeMergeTree 在 ClickHouse 中是一种表引擎,专为高数据摄取速率和大数据量而设计。它是 ClickHouse 的核心存储引擎,提供诸如列式存储、自定义分区、稀疏主索引以及对后台数据合并的支持等功能。 表中都有其自己的主索引,该索引在查询执行期间独立使用。

  • 在查询期间,索引允许 ClickHouse 跳过颗粒 (granules),从而减少 I/O 和内存使用,同时提高性能。

  • 您可以使用 mergeTreeIndex 表函数检查索引内容,并使用 EXPLAIN 子句监控索引使用情况。

在哪里可以找到更多信息

要深入了解 ClickHouse 中稀疏主索引的工作方式,包括它们与传统数据库索引的不同之处以及使用它们的最佳实践,请查看我们的详细索引 深入研究

如果您有兴趣了解 ClickHouse 如何以高度并行的方式处理由主索引扫描选择的数据,请参阅查询并行性指南 此处

    © . This site is unofficial and not affiliated with ClickHouse, Inc.