我们是如何为 ClickHouse 列式存储构建快速 UPDATE 的 Part1/3:特别设计的专用引擎

Clickhouse实战--数据更新和删除概述_clickhouse update 在Clickhouse中可以有多种方法来更新数据,不同方法适用的场景不同。总的来说,在CK中更新数据方法有以下几种:(1)直接使用update语句(2)先删除数据,再插入最新的数据(3)ReplacingMergeTree表引擎+Insert语句(4)CollapsingMergeTree表引擎+Insert语句(5)VersionedCollapsingMergeTree表引擎+Insert语句。 阅读详情

图片

本文字数:9340;估计阅读时间:24 分钟

作者:Tom Schreiber

本文在公众号【ClickHouseInc】首发

How we built fast UPDATEs for the ClickHouse column store – Part 1: Purpose-built engines

要点总结

ClickHouse 通过将更新视作插入操作,巧妙避开了行级更新带来的性能瓶颈。在这篇系列的第一篇中,我们将介绍几个专为此场景设计的引擎,它们是如何实现高速更新的。  

在第 2 部分,我们将展示如何引入 SQL 风格的 UPDATE,同时仍保持 ClickHouse 的高性能优势。

不用 UPDATE 也能实现快速更新 

列式存储天生不适合做行级更新。

ClickHouse 也不例外:它从一开始就是为了在大规模数据场景下提供极速的写入和查询性能而设计的,而不是为修改单行数据而优化的。

但现实中的数据应用并不会遵循教科书上的“只读”模式。

ClickHouse 的用户经常要处理快速变化的数据:IoT(传感器读数)、电商(订单与库存)、金融(支付状态)、游戏(玩家数据),以及 CRM/HR(用户或员工档案),这些数据需要被不断地更正、更新甚至删除。与其在一个为大规模读取设计的系统中硬塞进低效的 UPDATE 操作,我们选择了另一种方式:

我们将更新操作当作插入来处理,从而绕开了性能问题。

这不是一个临时解决方案,而是 ClickHouse 有意为之的架构设计。像 ReplacingMergeTree、CoalescingMergeTree 和 CollapsingMergeTree 这样的引擎,通过写入新行代替修改旧行,实现了对更新和删除的支持。它们充分利用 ClickHouse 高并发插入能力和后台合并机制,避开了原地更新常见的性能开销。

这些引擎在大规模数据场景中依然非常实用,尤其适合高写入、频繁变更的数据工作负载。同时,它们也为我们后来构建的新一代更新机制提供了灵感,理解它们的工作方式,有助于理解 ClickHouse 如何加速 SQL 风格的更新。

本系列将介绍以下内容:

  • 本篇(第 1 部分):介绍这些专为处理更新而设计的引擎是如何工作的,以及为何它们依旧非常高效。

  • 第 2 部分(https://clickhouse.com/blog/updates-in-clickhouse-2-sql-style-updates):将介绍如何引入标准 SQL 风格的 UPDATE,并由一种全新的机制 —— patch parts 提供支持。

  • 第 3 部(https://clickhouse.com/blog/updates-in-clickhouse-3-benchmarks):我们将对上述所有方案进行性能测试,对比它们在实际场景中的表现。

要理解 ClickHouse 是如何做到快速更新的,首先得知道为什么列式存储天生就不擅长处理更新操作。

为什么在列式存储中执行更新很困难 

在数据库系统中,更新与分析常常是性能上的对立面:一个优化了,另一个可能就会变慢。

在行式存储系统(如 PostgreSQL 或 MySQL)中:

  • 每一行数据在磁盘上是连续存储的。

  • 所以更新很方便,可以直接原地覆盖整行。

  • 但分析性能不佳:即便你只查询两列,也必须把整行加载到内存中。

而在列式存储系统(如 ClickHouse)中:

  • 每一列被存储为独立的文件。

  • 因此分析非常高效,只需读取所需的列。

  • 但更新变得更复杂,因为要修改某一行数据,必须同时修改多个文件,且需要重写部分数据。

这种结构性的取舍,让列式系统始终难以高效支持行级更新。

ClickHouse 选择了另一种思路:用专为此场景设计的引擎,通过“避开更新”来实现更新。

由于插入非常快,我们将更新实现为插入

核心理念其实很直接:ClickHouse 对插入操作做了极致优化。由于没有像全局 B++ 索引这样的集中结构需要锁定或维护,插入操作彼此完全隔离(https://clickhouse.com/docs/concepts/why-clickhouse-is-so-fast#storage-layer-concurrent-inserts-are-isolated-from-each-other),可以并发执行,互不干扰,且以全速写入磁盘(某些生产环境下甚至实现了 每秒超 10 亿行(https://clickhouse.com/blog/how-tesla-built-quadrillion-scale-observability-platform-on-clickhouse#proving-the-system-at-scale) 的写入)。这也意味着表无论多大,插入性能都不会下降。此外,插入过程非常轻量:诸如记录替换之类的逻辑被拆分出去,延迟到后台合并时再处理(https://clickhouse.com/docs/concepts/why-clickhouse-is-so-fast#storage-layer-merge-time-computation)。

关键在于:正因为插入足够高效,ClickHouse 可以把更新(甚至删除)当作额外的插入来处理。

在像 IoT 这样需要高吞吐的数据场景中,传统 SQL 风格的 UPDATE 操作其实并不高效:即使是在关系型数据库中,更新一条记录也往往涉及查找旧值、重写整行,甚至加锁或额外更新许多不必要的数据。

而 ClickHouse 的专用引擎如 ReplacingMergeTree、CoalescingMergeTree 和 CollapsingMergeTree,则采用了一种更高效的“只插入”模型:完全跳过了查找旧记录的过程。更新和删除操作都被转换为快速、轻量的插入行为,实际的数据更改则交由后台合并过程异步完成。

为什么这种方式如此高效:ClickHouse 本身就会在后台不断地将小的数据分片 合并(https://clickhouse.com/docs/merges) 成更大的 分片(https://clickhouse.com/docs/parts),这正是其存储引擎名称 MergeTree 的由来。合并过程中,系统会将相关数据加载到内存中、进行整理并写出一个新的分片。既然这些合并操作本来就要进行,因此顺便处理更新或删除几乎不会带来额外开销。保留某条记录的最新版本或移除已取消记录的代价非常小。

ClickHouse 能够实现这种轻量的 *插入-合并* 流程,关键就在于它的数据在磁盘上的组织方式:数据被分割成有序、不可变的分片,并持续在后台合并。

理解数据部分与合并机制

想深入理解 ClickHouse 如何实现快速更新,以及更好地阅读本文(和下一篇)中的图示和机制说明,有必要先了解一切的基础 —— 分片(parts)。

插入会生成已排序且不可变的数据部分

每当你向 ClickHouse 表插入数据时,系统都会在磁盘上写入一个独立的、不可变的 数据分片(https://clickhouse.com/docs/parts)。

每个分片包含若干行数据(按列存储),并根据其在插入和合并历史中的位置命名。例如,向一个初始为空的 orders 表插入包含 order_id、item_id、quantity、price 和 discount 列的数据后:

INSERT INTO orders VALUES
    (1001, 'kbd',   10, 45.00, 0.00),
    (1001, 'mouse',  6, 25.00, 0.00);

ClickHouse 会生成一个名为 all_1_1_0 的新分片:

图片

该分片中的数据在磁盘上是按照表的排序键排序的,在这个例子中是 (order_id, item_id)。这一点适用于所有 MergeTree 表的分片,是 ClickHouse 能高效合并数据、避免随机 I/O 和重新排序的关键。

如何解读部分的名称

每个分片的命名遵循 partition_minBlock_maxBlock_mergeLevel 格式,其中:

  • all 表示 分区(https://clickhouse.com/docs/partitions) ID(此处使用默认分区)

  • 1 是该分片中包含的 最小块号

  • 1 是该分片中包含的 最大块号

  • 0 表示 合并层级(https://clickhouse.com/docs/merges#what-are-part-merges-in-clickhouse),0 表示初始插入,数字越大代表合并层级越高

部分包含的内容

在系统底层,这个分片其实是磁盘上的一个文件夹,名为 all_1_1_0,其中包含表中每一列的数据文件:order_id、item_id、quantity、price 和 discount。每个文件都经过压缩,存储了该分片中对应列的所有值。

上图展示了这些列文件的结构,帮助理解分片内部的数据布局。

块如何组成一个部分

ClickHouse 插入数据的基本单位是 数据块(block),每个块会分配一个 单调递增的块号。一个分片可能包含一个或多个块,可能来源于单次插入,也可能是多个分片合并后的结果。分片名中的 minBlock 和 maxBlock 表示该分片所包含数据块号的范围。

合并在后台自动进行

当新的数据到来时,ClickHouse 不会修改已有的分片,而是生成新的分片写入磁盘。后台机制则会不断 合并(https://clickhouse.com/docs/merges) 这些分片,以控制数量并整理数据。

已排序的数据部分让合并更高效

ClickHouse 能够高效合并分片,原因在于所有分片都已经按照相同的列顺序排好序。合并两个分片时,引擎只需顺序扫描二者并将数据交错写入,无需重新排序、无需随机读取,也不需要使用临时缓存。

这被称为 单次合并扫描(single merge pass):ClickHouse 顺序读取两个分片,实时对比每一行并写出新的合并结果。这正是其合并操作既快速又轻量的核心原因之一。

这种高效机制意味着,在合并过程中处理更新和删除操作几乎不会带来额外负担,它们也只是同一个扫描和写入流程中的一部分。

了解了底层原理后,我们接下来通过实际案例来看看它是如何运作的,首先从最简单直接的引擎开始:ReplacingMergeTree。

ReplacingMergeTree:通过插入新行替换旧行

我们用一个五金店的订单表作为示例,来演示 ReplacingMergeTree(https://clickhouse.com/docs/engines/table-engines/mergetree-family/replacingmergetree) 的用法:

CREATE TABLE orders (
    order_id   Int32,
    item_id    String,
    quantity   UInt32,
    price      Decimal(10,2),
    discount   Decimal(5,2)
)
ENGINE = ReplacingMergeTree
ORDER BY (order_id, item_id);

要更新一条记录,只需要插入一条具有相同排序键 (order_id, item_id) 的新版本。在后台合并时,ClickHouse 会自动保留最新的那条记录(即最后插入的一条)。例如,假设客户 ① 一开始订购了 10 个键盘和 6 个鼠标,按原价计费:

INSERT INTO orders VALUES
    (1001, 'kbd',   10, 45.00, 0.00),
    (1001, 'mouse',  6, 25.00, 0.00);

后来他将鼠标的数量提高到了 60 个,享受了 20% 的批量折扣。这时候,我们不修改旧数据,而是通过 ② 插入一条包含更新后的数量和折扣的新记录:

INSERT INTO orders VALUES
    (1001, 'mouse', 60, 25.00, 0.20);

下图展示了最初插入(①)和更新插入(②)所创建的 数据分片(https://clickhouse.com/docs/parts)。在下一轮 后台合并(https://clickhouse.com/docs/merges)(③)中,ClickHouse 会自动丢弃旧版本,只保留最新的记录:

图片

合并之后,分片 ① 和 ② 将被清除,分片 ③ 成为该表的 活跃数据分片。

那么,如果你只需要更新部分字段怎么办?这就是 CoalescingMergeTree 派上用场的时候。

CoalescingMergeTree:自动合并部分更新

CoalescingMergeTree(https://clickhouse.com/docs/engines/table-engines/mergetree-family/coalescingmergetree) 的机制与 ReplacingMergeTree 十分类似,但有一个显著不同:它支持 部分更新(partial updates)。你可以只插入有变动的字段,无需整行覆盖。

我们继续使用同一个订单表:

CREATE TABLE orders (
    order_id   Int32,
    item_id    String,
    quantity   Nullable(UInt32),
    price      Nullable(Decimal(10,2)),
    discount   Nullable(Decimal(5,2))
)
ENGINE = CoalescingMergeTree
ORDER BY (order_id, item_id);

注意:非排序键的字段被设为 Nullable 类型,这样在执行部分更新时,可以省略未变更的列,未指定的字段会被自动设为 NULL。

还是同一个例子:客户 ① 一开始订购了 10 个键盘和 6 个鼠标,按原价计费:

INSERT INTO orders VALUES
    (1001, 'kbd',   0, 45.00, 0.00),
    (1001, 'mouse', 6, 25.00, 0.00);

② 我们插入一条仅更新数量和折扣的记录:

INSERT INTO orders VALUES
    (1001, 'mouse', 60, NULL, 0.20);

当后台将 ① 初始插入和 ② 更新插入进行合并时,会生成一个新的数据分片 ③,ClickHouse 会针对每一列保留最新的非空值,从而将多条部分更新记录合并为一条完整记录。合并完成后,① 和 ② 分片将被丢弃,整个流程与 ReplacingMergeTree 相同:

图片

想了解典型场景和底层机制,请阅读 CoalescingMergeTree 的详细介绍(https://clickhouse.com/blog/clickhouse-25-6-coalescingmergetree)。

那如果是删除操作呢?CollapsingMergeTree 提供了一种巧妙的方式来处理。

CollapsingMergeTree:通过插入新行来删除旧行

CollapsingMergeTree(https://clickhouse.com/docs/engines/table-engines/mergetree-family/collapsingmergetree) 允许你无需发出 DELETE 语句即可删除记录。其做法是插入一条特殊的“取消”行,用以标记原始记录无效。

我们还是用之前的订单表,不过这次我们为其添加了一个额外的 is_valid 字段,用作该引擎的 sign 参数(https://clickhouse.com/docs/engines/table-engines/mergetree-family/collapsingmergetree#parameters):

CREATE TABLE orders (
    order_id   Int32,
    item_id    String,
    quantity   UInt32,
    price      Decimal(10,2),
    discount   Decimal(5,2),
    is_valid   UInt8 -- only required for CollapsingMergeTree
)
ENGINE = CollapsingMergeTree(is_valid)
ORDER BY (order_id, item_id);

① 初始插入一条订单:

INSERT INTO orders VALUES
    (1001, 'kbd',  10, 45.00, 0.00, 1),
    (1001, 'mouse', 6, 25.00, 0.00, 1);

② 若要删除这条记录,我们插入一条相同排序键 (order_id, item_id) 的新行(其余字段可为 NULL),并将 is_valid 设为 -1:

INSERT INTO orders VALUES
    (1001, 'mouse', NULL, NULL, NULL, -1);

在接下来的 ③ 合并过程中,ClickHouse 会找到对应的 +1 和 -1 两条记录并将它们折叠合并,从而一并移除,连带着分片 ① 和 ② 也会被清除:

图片

这一机制同样可以用于 更新操作:要更新一条记录,只需先插入一条取消记录,再插入新的值版本。在下一轮后台合并中,旧值和取消记录将被移除,只保留最新的记录。  

CollapsingMergeTree 甚至支持更新排序键字段,这是 ReplacingMergeTree 和 CoalescingMergeTree 无法实现的功能。

除了支持更新和删除,这三种引擎还都具备 UPSERT 能力。

额外特性:内置 UPSERT 行为

无论是 ReplacingMergeTree、CoalescingMergeTree,还是 CollapsingMergeTree,都支持实质上的 UPSERT(插入或更新):当插入新行时,如果存在相同排序键的记录,引擎会自动应用对应逻辑进行合并。

这种“插入即更新”的模式非常强大,而标准的 UPDATE 语句并不具备直接支持这种用法的能力。

虽然 SQL 标准定义了 MERGE(https://en.wikipedia.org/wiki/Merge_\(SQL\)) 命令来实现插入或更新逻辑,但它通常写法繁琐,执行效率也不高。而在 ClickHouse 中,这一切只需要一次简单、快速的插入操作即可完成。

基于插入的模型为 ClickHouse 带来了高效的更新、删除和 UPSERT 能力。但如果你希望查询结果在后台合并完成之前就反映出这些更改,该怎么处理呢?

使用 FINAL 获取最新结果

上述三种表引擎都依赖后台合并来整合数据。这种方式让插入驱动的更新和删除变得极为高效,但也意味着这些操作是“最终一致”的:在高并发写入场景下,插入可能超过合并的处理速度,也就是存在一个数据尚未整合的窗口期。

为确保此时查询结果的准确性,ClickHouse 提供了一个机制:在查询时 即时应用引擎的合并逻辑,通过 FINAL(https://clickhouse.com/docs/sql-reference/statements/select/from#final-modifier) 修饰符实现。

SELECT * FROM orders FINAL;

使用 FINAL 时,并不会真正触发磁盘上的合并,而是通过内存将相关的数据分片动态整合,以查询发起时的数据状态为基础,返回已经合并后的结果。

在三种引擎中,FINAL 表现一致:

  • 在 ReplacingMergeTree 中,它会保留每条记录的最新版本;

  • 在 CoalescingMergeTree 中,它将稀疏更新合并为完整行;

  • 在 CollapsingMergeTree 中,它应用取消逻辑来处理删除与更新。

因此,在你需要数据一致性强、结果准确可控的查询场景中,FINAL 是一个强有力的工具,同时保留了基于插入操作的高吞吐性能。

无需惧怕 FINAL

ClickHouse 针对 FINAL 做了大量 优化(https://clickhouse.com/blog/clickhouse-release-23-12#optimizations-for-final):包括智能内存算法、跳过无冲突分片的选择性处理、以及向量化执行等技术,使得即使在海量数据下,FINAL 的执行依然高效。对于不涉及冲突的分片范围,ClickHouse 会直接跳过处理。每列还会 独立并行处理(https://clickhouse.com/blog/clickhouse-release-24-01#vertical-algorithm-for-final-with-replacingmergetree),进一步降低内存消耗,并提升宽表下的整体性能。

你可以拿到正确的结果——但这真的算是“更新”操作吗?我们稍作停顿,从更高的视角来重新理解。

这与真正的更新有何不同?

从整体视角来看,ClickHouse 的更新模式其实与传统行式数据库非常相似:写入新版本,再读取新版本。

传统行式数据库

ClickHouse

原地覆盖旧数据

在旧数据旁追加新版本

查询立即返回新版本

查询同样立即返回新版本

提交写入后旧版本被删除

旧版本稍后由后台合并清理

也就是说,虽然内部机制不同,尤其是在数据清理上有所延后,但其“更新语义”却高度一致。

然而,要获得这种一致性的效果,你必须采用 ClickHouse 的思维方式。这意味着理解后台合并原理、知道何时使用 FINAL,以及选择适合的表引擎。你需要将每次更新建模为一次插入,同时根据各引擎特性来设计数据模型。例如,ReplacingMergeTree 要求通过排序键来识别记录,一旦排序键发生变化,往往需要重建整张表。

这种模型并不符合传统 SQL 用户对 UPDATE 操作的直觉。

从引擎语义到 SQL 的简洁性

虽然这些专用引擎具备极高的性能和灵活性,但也带来了学习曲线。用户需要考虑合并机制、排序键行为,以及不同引擎的具体实现方式——这就让 UPDATE 操作远不像标准 SQL 那般直观易用。

为此,ClickHouse 也在持续演进。

在 第 2 部分(https://clickhouse.com/blog/updates-in-clickhouse-2-sql-style-updates) 中,我们将介绍如何将 快速、SQL 风格的 UPDATE 操作 引入 ClickHouse,同时保留其一贯的高性能特性。

我们会完整回顾这一演进路径:从早期的“重量级” mutation,到基于引擎机制的轻量即时更新,最终发展出由 patch parts 驱动的声明式更新方式。这是一种全新的可扩展机制,汲取了上一节中几种引擎的设计理念,同时实现了统一封装,并通过熟悉的 SQL 语法对外呈现。

换句话说,ClickHouse 已经提供了 UPDATE 所应具备的一切能力——只是以它特有的高性能方式实现。

征稿启示

面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

Clickhouse的数据存储原理、二进制文件内容分析与索引详解 阅读详情

相关推荐

ClickHouse入门与实战:列式存储、向量化与查询优化全解析

在数据分析场景中,传统行式数据库面对海量明细表的聚合查询往往力不从心。OLAP 分析型数据库通过列式存储将同类数据连续存放,大幅减少无效 IO,配合向量化执行利用 CPU SIMD 指令批量处理数据,让扫描速度提升数个量级。ClickHouse 正是这一技术的典型代表,它专为宽表聚合、大范围扫描设计,支持 MergeTree 引擎、分区裁剪、物化视图等优化手段,可有效解决看板报表、用户行为分析等实时查询难题。文章从核心原理出发,结合安装部署、数据类型选型、SQL 写法与调优技巧,并针对认证失败、精度翻车、备

weixin_34289454的博客 255

【ClickHouse】Clickhouse中update/delete的使用

从使用场景来说,Clickhouse是个分析型数据库。这种场景下,数据一般是不变的,因此Clickhouse对update、delete的支持是比较弱的,实际上并不支持标准的update、delete操作。 下面介绍一下Clickhouse中update、delete的使用。 1. 更新和删除的语法 Clickhouse通过alter方式实现更新、删除,它把update、delete操作叫做mutation(突变)。语法为: ALTER TABLE [db.]table DELETE WHERE

天天新知 2万+

【Clickhouse从入门到精通】第21篇:ClickHouse MergeTree二级索引与数据存储压缩机制

摘要 本文深入解析ClickHouse MergeTree引擎的跳数索引与数据压缩机制。跳数索引通过数据块级过滤器(minmax/set/bloom_filter/ngrambf_v1)帮助查询跳过无关数据块,显著提升非主键列查询效率;数据压缩采用列式块压缩(LZ4/ZSTD)大幅降低存储空间,同时保持高效读取性能。文章详细介绍了各类跳数索引的原理、适用场景与创建语法,分析了压缩算法选择与参数调优策略,并通过实战案例展示索引优化效果。这两项核心技术共同构成了ClickHouse高效存储与查询的重要基础。 关

xyghehehehe的专栏 389

Clickhouse UPDATE 和 DELETE操作

在OLAP数据库中,可变数据(Mutable data)通常是不被欢迎的,Clickhouse也是如此,早期版本不支持UPDATE和DELTE操作。在Clickhouse 1.1.54388版本之后才支持UPDATE和DELETE操作,适用于MergeTree引擎,并且这种操作方式是异步的(asynchronous),但是在一些交互场景下很难使用。Clickhouse提供了delete和update操作,这类操作被称之为Mutation查询,是ALTER语句的变种。

LuckyTHP 4727

【Clickhouse从入门到精通】第15篇:ClickHouse数据表操作与数据分区管理

摘要 本文深入解析ClickHouse数据表操作与分区管理机制,涵盖ALTER TABLE语句的各类用法、数据分区策略、分布式DDL执行等核心功能。通过实战案例演示如何追加字段、修改数据类型、添加备注及删除字段等常见操作,并详细说明ClickHouse特有的分区管理与数据修改机制。文章为开发者提供ClickHouse数据表管理的全面指导,帮助构建高效可靠的数据存储方案。 关键词:ClickHouse、ALTER TABLE、数据分区、分布式DDL、mutation

xyghehehehe的专栏 353

ClickHouse容量统计实战:用system.parts精准定位库表大小

在数据库运维中,容量监控是保障集群稳定运行的基础。当面临磁盘告警时,如何快速定位哪张表占用了大量空间,是每位ClickHouse使用者都需掌握的技能。ClickHouse基于MergeTree引擎将数据拆分为多个part存储,因此物理容量的精确统计需要从part粒度出发。系统表system.parts完整记录了每个part的行数、压缩前后字节数及磁盘占用等关键元数据,是数据库容量管理与表大小查询的核心数据源。与system.tables中的total_bytes相比,system.parts支持按库、表、分

weixin_34268753的博客 269

【最佳实践指南】在ClickHouse中更新和删除数据

对于一个分析型数据库而言,更新和删除数据是有挑战的,它会显著影响数据库的性能。为了解决这个问题,ClickHouse为不同场景提供了不同的高效更新和删除数据方式:Lightweight删除,通过语句从ClickHouse里删除数据。这是删除数据最高效的方式,适合无需立即释放磁盘空间、允许数据继续存留在磁盘上的场景;Mutation删除,通过语句删除。适合需要立即释放磁盘空间的场景。例如,合规要求需要确保数据从磁盘上删除。Mutation更新,通过语句更新。适合不会频繁更新数据的场景使用TTLs。

IT部落格 1万+

ClickHouse安装部署全攻略:从环境准备到生产配置

在线分析处理(OLAP)是处理海量数据分析的核心技术范式,其核心原理在于通过列式存储、向量化执行等设计,优化数据读取与聚合计算效率,从而在数据仓库、实时报表等场景中实现亚秒级查询响应。这一技术价值在于能够大幅降低大数据分析的系统复杂性与查询延迟,尤其适用于用户行为分析、物联网监控等需要快速洞察的领域。本文聚焦于高性能OLAP数据库ClickHouse的实战部署,深入解析其安装前的硬件环境检查、版本选择策略,并对比包管理器、二进制包与Docker三种主流安装方式的优劣与具体操作步骤,帮助读者快速构建稳定可靠的

weixin_30239339的博客 375

ClickHouse UPDATE原理:MergeTree专用引擎如何实现快速更新

在列式存储架构下,传统意义上的就地UPDATE几乎是一个伪命题:每列独立存储、数据块压缩、级联元数据失效,都让每次修改演变为全表规模的重写。ClickHouse却通过Append-Only写入与后台合并机制,将更新从写入路径的沉重负担转化为后台异步的轻量操作,从而在特定场景下甚至比原地更新型数据库更快。这背后依赖的是MergeTree家族中几类专用引擎的设计——ReplacingMergeTree以版本号完成最终态压缩,CollapsingMergeTree通过正负行抵消实现状态折叠,Aggregating

weixin_33491377的博客 269

ESP32+MAX7219二进制时钟设计与嵌入式时间映射实践

二进制时钟是嵌入式系统中数据表示与物理呈现深度耦合的典型范例,其核心在于将时间语义(年月日时分秒)解构为比特位,并通过LED点阵的空间权重布局实现直观识别。该设计依托RTC模块提供时间基准,依赖SPI协议完成微控制器与专用驱动芯片(如MAX7219)的可靠通信,涉及寄存器级配置、位图坐标变换、软硬件时序对齐等关键原理。技术价值体现在低资源占用下的高可读性人机交互,适用于教学演示、极客项目及嵌入式UI原型开发。本文聚焦ESP32平台在MicroPython环境下,结合MAX7219驱动8×8点阵实现高可靠性二

weixin_42160645的博客 301

Vivado时序违约小结

目录1. setup time违约1.1 逻辑级数太高1.2 Fanout太大2. hold time 违约2.1 异步信号处理导致hold time违约 1. setup time违约 建立时间是工程设计中最常遇到的问题了。一般说来,导致建立时间违例主要有两个原因:逻辑级数太大或者扇出太大,当然也可以尝试通过降频来解决建立时间违约。 1.1 逻辑级数太高 Levels指的是逻辑级数logic level,一个logic level的延迟对应的是一个LUT和一个Net的延迟,对于不同的器件,不同频率的设计能

mu_guang_的博客 7155

ClickHouse Lightweight Delete原理解析及ClickHouse Mutation设计框架解析

我们在研发ClickHouse Decommission/Rebalance Tool的时候,需要对ClickHouse的Part的生命周期以及状态转移进行研究,确保我们的Tool在数据安全层面没有任何问题。本文就是其中的一个特别重要的关注点: 即,新版ClickHouse所支持的旁路补丁型的修改,这种修改方式极其特殊,它不像任何普通修改一样,采用Part的实时切换(修改以后的Part替换掉修改前的旧Part),而是,补丁(Patch)本身作为一个独立的Part对原始Part进行查询结果修正,并且这个Pat

小昌昌的博客 286

从手机到单片机:聊聊ARM Cortex家族那些事,A、R、M系列到底有啥不同?

本文深入解析ARM Cortex家族的A、R、M三大系列处理器,揭示它们在性能、实时响应和能效方面的核心差异。从智能手机到汽车电子和物联网设备,Cortex-A、R、M各司其职,分别应对复杂运算、实时控制和超低功耗场景。通过技术指标对比和典型应用案例,帮助开发者理解如何根据DMIPS/MHz等关键参数选择适合的处理器架构。

weixin_31574149的博客 350

ClickHouse实战指南:从选型部署到性能优化与故障排查

在OLAP分析需求日益增长的背景下,列式存储数据库凭借其高吞吐、低延迟的聚合查询能力,成为大数据分析场景中的热门选择。ClickHouse通过按列存储与向量化执行引擎,大幅减少磁盘IO,在TB级数据量下实现秒级响应,为报表、监控大盘等场景提供了高效支撑。同时,分布式集群的部署与管理是落地过程中的关键环节,涉及分片、副本、Keeper协调及认证配置等细节,稍有不慎便会引发连接异常。数据安全方面,全量快照加增量备份的结合能有效降低误操作风险;而在性能调优上,建表设计、SQL写法与系统监控缺一不可。本文从选型判断

weixin_34072637的博客 151

《AI 时代FPGA的全栈开发实战・从入门到精通》专栏启动说明

《智驱FPGA》专栏面向初学者,聚焦AI时代FPGA开发新范式,以ChatGPT、ICCoder2.0等工具全程辅助,覆盖纯逻辑、Zynq软硬协同、端侧AI加速、高速接口等核心方向。通过126节图文+14个实战项目,传授AI生成代码、Prompt工程、时序优化等能力,助力学员从零成长为具备工程竞争力的FPGA工程师,结业可独立完成完整项目并写入简历。

现任某外企的算法工程师!专注于人工智能、嵌入式、FPGA、论文写作四大主题的教程和经验分享!辅导请➕v :sci666888999 172

yolov11添加P2小目标检测头与添加P6超大目标检测头

本文介绍了YOLO目标检测模型中上下采样的原理及应用。上采样通过插值算法放大特征图,YOLO通常采用最近邻插值;下采样则通过带步长的卷积缩小特征图提取高层语义特征。文章详细阐述了这两种操作在YOLO中的实现方式、结构特点及对称性问题,指出下采样后会使用C3模块进行特征整合,上采样后通过concat抑制分割感。此外,还分析了不同分辨率特征图适合检测不同尺寸目标的原因,并提出添加4倍小目标检测头的方法,即对上采样后的特征进行concat和C3模块处理。最后给出了YOLOv5原模型结构和添加4倍检测头后的结构对比

m0_64661770的博客 820

ClickHouse 集群建表实战:从引擎选择到本地表 / 分布式表落地

本文系统解析 ClickHouse 集群建表核心问题:从 MergeTree、ReplacingMergeTree 到 ReplicatedReplacingMergeTree 引擎选择,详解版本字段、ZooKeeper 路径与副本名配置逻辑。明确“本地表存数据、分布式表路由查询”的架构原则,结合业务场景推导分区键、排序键及参数设置,提供可复用的“环境+业务→参数”决策链,实现高效、可靠的生产级建表实践。

小小默:进无止境 412

2、OTA/gm - C滤波器的架构与设计

本文深入探讨了OTA/gm-C滤波器的两种主要设计方法:基于LC梯形网络的设计与多环反馈(MLF)结构。前者包括元件替代法和信号模拟法,分别通过电感替代或电路方程模拟实现低敏感度滤波器;后者通过积分器级联与反馈网络合成全极点或含任意传输零点的传递函数。文中详细分析了不同结构如IFLF和LF的反馈矩阵、传递函数及性能差异,指出LF结构在敏感度、噪声和整体性能上的优势。同时比较了各类方法的优缺点及适用场景,为高频连续时间集成电路滤波器的设计提供了系统性指导。

fanta的博客 137

ClickHouse 增删改查实战:从 MySQL 思维到 Mutation 机制

数据库的增删改查是日常操作,但不同存储引擎的底层实现差异巨大。ClickHouse 作为 OLAP 分析型数据库,采用列式存储与 MergeTree 引擎,数据以不可变 part 形式存储,因此 UPDATE 和 DELETE 实际上是通过 ALTER TABLE 触发的异步 mutation 任务,经过重写 part 与后台合并才最终生效。理解这一机制,是从 MySQL 迁移到 ClickHouse 的关键。合理设计分区键与排序键、批量写入、利用 TTL 和 DROP PARTITION 清理数据,能大幅

weixin_32050773的博客 212

【QCA6174】QCA6174 DFS认证的时候会有概率信道不会跳转的情况,通常跳转成功概率只有25%问题分析及解决方案

Master设备需要测试的项目。

wgl307293845的博客 752

AE-扭曲-变形-弧

一些AE效果的着色器实现记录

What_can_you_do的博客 1174

ClickHouse复制表与分布式表:生产环境高可用与扩展实践

在分布式数据库架构中,高可用与水平扩展是生产环境的核心诉求。当单机性能达到瓶颈,数据冗余与跨节点查询成为必须解决的工程问题。ClickHouse通过Replicated*MergeTree复制表与Distributed分布式表,构建了完整的集群解决方案:复制表基于ZooKeeper协调元数据,以异步方式在副本间同步数据Part,保障数据安全与节点自愈;分布式表作为统一查询入口,通过分片键将数据路由至不同分片,实现横向扩展与查询聚合。两者结合的双层表设计,既能应对节点故障,又能支撑海量数据场景下的低延迟分析。

weixin_34414196的博客 421

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Doris vs ClickHouse:OLAP引擎选型详解,从架构到运维的6大核心差异

OLAP(联机分析处理)引擎是数据仓库与实时分析平台的核心组件,常见的列式存储与MPP架构决定了系统在查询性能、数据更新和扩展能力上的表现。在技术选型时,Doris与ClickHouse常被放在一起比较:Doris凭借FE/BE架构实现对复杂Join查询的自动优化,而ClickHouse以向量化执行引擎在单表聚合场景中展现极致性能。两者在数据更新模型上差异显著,Doris的Unique Key支持秒级实时写入,ClickHouse则依赖Mutation机制,高频更新成本较高。部署与运维层面,Doris兼容M

weixin_34234721的博客 412

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

ClickHouse复制表与分布式表的原理、实操与避坑指南

分布式数据库常面临同一个问题:数据既要冗余备份,又要水平扩展。ClickHouse通过Replicated*MergeTree引擎与Distributed表引擎分别处理这两件事。复制表基于ZooKeeper协调副本间的part日志同步,实现多节点数据一致性;分布式表则负责跨分片的路由、写入分发与两阶段聚合,让查询像操作单表一样访问整个集群。理解两者组合逻辑,有助于设计高可用、可扩展的分析型架构。从副本同步、part拉取到internal_replication参数调优,再到集群故障排查,本文结合真实踩坑经验

weixin_33795806的博客 352

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Debian 10 部署 ClickHouse 生产实践:稳定性、性能与避坑指南

ClickHouse 是面向海量数据实时分析的高性能列式数据库,其核心价值在于亚秒级聚合查询与高吞吐写入能力。实现这一能力的前提是底层操作系统与数据库引擎的深度协同——尤其在内存管理、文件系统行为和CPU缓存对齐等关键环节。Debian 10 作为长期支持发行版,凭借稳定的内核(5.10 LTS)、标准化软件栈(glibc 2.28/systemd 241)及对 NUMA 和 mmap 的良好支持,成为 ClickHouse 生产部署的优选基础平台。本文聚焦真实场景下的技术落地:从禁用 transparen

weixin_30617737的博客 385

ClickHouse v24.3.4 LTS 补丁版技术解析:47 项修复背后的关键机制与升级影响

本篇文章基于仓库内官方发布记录 [docs/changelogs/archive/v24.3.4.147-lts.md](https://link.gitcode.com/i/31ae066312b68c01bb2a709040d482c6),对 ClickHouse 24.3 系列这一 LTS(长期支持)分支的补丁版本 v24.3.4.147-lts 做一次系统性的技术解读。该版本相对前一补丁

gitblog_00918的博客 657
上一篇: ClickHouse 内部的全文搜索:快速、原生、列式架构
下一篇: 我们是如何为 ClickHouse 列式存储构建快速 UPDATE 的 Part2/3:类 SQL 的 UPDATE
ClickHouseDB
博客等级 码龄3年 1707粉丝 320原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值