2022-04-10 23:08:18 +00:00
|
|
|
|
---
|
2022-08-26 19:07:59 +00:00
|
|
|
|
slug: /zh/faq/general/why-clickhouse-is-so-fast
|
2024-01-17 05:33:02 +00:00
|
|
|
|
title: 为什么 ClickHouse 如此快速?
|
2022-04-10 23:08:18 +00:00
|
|
|
|
toc_hidden: true
|
|
|
|
|
sidebar_position: 8
|
|
|
|
|
---
|
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
# 为什么 ClickHouse 如此快速? {#why-clickhouse-is-so-fast}
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
它被设计成一个快速的系统。在开发过程中,查询执行性能一直是首要考虑的优先级,但也考虑了其他重要特性,如用户友好性、可扩展性和安全性,使 ClickHouse 成为一个真正的生产系统。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
ClickHouse 最初是作为一个原型构建的,它的单一任务就是尽可能快速地过滤和聚合数据。这正是构建典型分析报告所需做的,也是典型 [GROUP BY](../../sql-reference/statements/select/group-by.md) 查询所做的。ClickHouse 团队做出了几个高层次的决策,这些决策组合在一起使得实现这一任务成为可能:
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
列式存储
|
|
|
|
|
: 源数据通常包含数百甚至数千列,而报告可能只使用其中的几列。系统需要避免读取不必要的列,否则大部分昂贵的磁盘读取操作将被浪费。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
索引
|
|
|
|
|
: ClickHouse 在内存中保留数据结构,允许不仅读取使用的列,而且只读取这些列的必要行范围。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
数据压缩
|
|
|
|
|
: 将同一列的不同值存储在一起通常会导致更好的压缩比(与行式系统相比),因为在实际数据中列通常对相邻行有相同或不太多的不同值。除了通用压缩之外,ClickHouse 还支持 [专用编解码器](../../sql-reference/statements/create/table.mdx/#create-query-specialized-codecs),可以使数据更加紧凑。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
向量化查询执行
|
|
|
|
|
: ClickHouse 不仅以列的形式存储数据,而且以列的形式处理数据。这导致更好的 CPU 缓存利用率,并允许使用 [SIMD](https://en.wikipedia.org/wiki/SIMD) CPU 指令。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
可扩展性
|
|
|
|
|
: ClickHouse 可以利用所有可用的 CPU 核心和磁盘来执行甚至是单个查询。不仅在单个服务器上,而且在集群的所有 CPU 核心和磁盘上。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
但许多其他数据库管理系统也使用类似的技术。真正使 ClickHouse 脱颖而出的是 **对底层细节的关注**。大多数编程语言为最常见的算法和数据结构提供了实现,但它们往往过于通用而无法高效。每个任务都可以被视为具有各种特征的景观,而不是仅仅随意投入某个实现。例如,如果您需要一个哈希表,这里有一些关键问题需要考虑:
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
- 选择哪种哈希函数?
|
|
|
|
|
- 冲突解决算法:[开放寻址](https://en.wikipedia.org/wiki/Open_addressing)还是[链接](https://en.wikipedia.org/wiki/Hash_table#Separate_chaining)?
|
|
|
|
|
- 内存布局:一个数组用于键和值还是分开的数组?它会存储小值还是大值?
|
|
|
|
|
- 填充因子:何时以及如何调整大小?在调整大小时如何移动值?
|
|
|
|
|
- 是否会移除值,如果会,哪种算法会更好?
|
|
|
|
|
- 我们是否需要使用位图进行快速探测,字符串键的内联放置,对不可移动值的支持,预取和批处理?
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
哈希表是 `GROUP BY` 实现的关键数据结构,ClickHouse 会根据每个特定查询自动选择 [30 多种变体](https://github.com/ClickHouse/ClickHouse/blob/master/src/Interpreters/Aggregator.h) 中的一种。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
算法也是如此,例如,在排序中,您可能会考虑:
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
- 将要排序的是数字数组、元组、字符串还是结构?
|
|
|
|
|
- 所有数据是否完全可用于 RAM?
|
|
|
|
|
- 我们需要稳定排序吗?
|
|
|
|
|
- 我们需要完全排序吗?也许部分排序或第 n 个元素就足够了?
|
|
|
|
|
- 如何实现比较?
|
|
|
|
|
- 我们正在对已经部分排序的数据进行排序吗?
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
他们所依赖的算法根据其所处理的数据特性,往往可以比通用算法做得更好。如果事先真的不知道,系统可以尝试各种实现,并在运行时选择最佳的一种。例如,看一篇关于 [ClickHouse 中 LZ4 解压缩是如何实现的文章](https://habr.com/en/company/yandex/blog/457612/)。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
最后但同样重要的是,ClickHouse 团队始终关注互联网上人们声称他们提出了最佳的实现、算法或数据结构来做某事,并尝试它。这些声称大多是虚假的,但有时你确实会找到一颗宝石。
|
2022-04-10 23:08:18 +00:00
|
|
|
|
|
2024-01-17 05:33:02 +00:00
|
|
|
|
:::info 构建高性能软件的提示
|
|
|
|
|
- 设计系统时要考虑到底层细节。
|
|
|
|
|
- 基于硬件能力进行设计。
|
|
|
|
|
- 根据任务的需求选择数据结构和抽象。
|
|
|
|
|
- 为特殊情况提供专门化。
|
|
|
|
|
- 尝试您昨天阅读的关于新的“最佳”算法。
|
|
|
|
|
- 根据统计数据在运行时选择算法。
|
|
|
|
|
- 在真实数据集上进行基准测试。
|
|
|
|
|
- 在 CI 中测试性能回归。
|
|
|
|
|
- 测量并观察一切。
|
2023-09-05 12:43:53 +00:00
|
|
|
|
:::
|