尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Langfuse 数据删除最佳实践:用轻量删除、ReplacingMergeTree 与 DROP PARTITION 取代 ALTER TABLE DELETE 突变

发布时间:2026/9/10 21:07:16

资讯中心
01
ARTICLE

Langfuse 数据删除最佳实践:用轻量删除、ReplacingMergeTree 与 DROP PARTITION 取代 ALTER TABLE DELETE 突变

Langfuse 数据删除最佳实践:用轻量删除、ReplacingMergeTree 与 DROP PARTITION 取代 ALTER TABLE DELETE 突变
Langfuse 数据删除最佳实践用轻量删除、ReplacingMergeTree 与 DROP PARTITION 取代 ALTER TABLE DELETE 突变【免费下载链接】langfuse Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse本文基于 Langfuse 仓库中的 ClickHouse 最佳实践规则文档insert-mutation-avoid-delete.md深入讲解为何必须规避ALTER TABLE DELETE这类数据突变mutation操作并结合 Langfuse 实际生产表结构traces / observations / scores / events 等展示 ReplacingMergeTree 软删除标记、轻量 DELETE 与按月分区 DROP PARTITION 的落地用法。读完本文你将掌握一套可插入、可删除、不重写的 ClickHouse 数据生命周期管理方案并能在 Langfuse 的仓库代码中找到每一处实践对应的实现依据。规则核心为什么ALTER TABLE DELETE是 CRITICAL 级反模式在 ClickHouse 中ALTER TABLE DELETE属于突变mutation操作它不是一个即时生效的普通删除而是一个异步后台进程凡是命中的 data part数据分片ClickHouse 都要把整个 part 读出来、剔除命中行、再重写回磁盘。这意味着写入放大严重哪怕只删几行只要这些行分散在多个 part 中所有相关 part 都会被完整重写磁盘 I/O 尖峰重写过程会抢占集群 I/O拖慢同一时刻的查询与写入不可回滚突变一旦提交无法撤销读不一致SELECT 可能读到已突变与未突变 part 混合的结果。该规则在规则文件 YAML 元数据中被标记为impact: CRITICAL即影响等级最高的约束项在 SKILL.md 的规则分类优先级表中Mutation Avoidance突变规避同样位列 CRITICAL 等级。规则文档给出的反模式示例非常典型-- Mutation delete for cleanup ALTER TABLE orders DELETE WHERE status cancelled; -- Time-based cleanup via mutation (very expensive) ALTER TABLE sessions DELETE WHERE created_at now() - INTERVAL 7 DAY;第一句按业务条件清理第二句按时间批量清理旧数据二者都命中大量 part代价高昂。接下来分别介绍三种正确替代方案。方案一CollapsingMergeTree——高频软删除的正确姿势针对频繁删除少量行的场景规则文档推荐使用折叠树引擎 CollapsingMergeTree。其核心思想是用插入替代删除为表增加一个sign列1 表示活跃-1 表示删除删除动作变成一次sign -1的普通插入折叠合并引擎会在后台把同一排序键下1/-1成对的数据自动抵消。规则文档中的完整示例CREATE TABLE orders ( order_id UInt64, customer_id UInt64, total Decimal(10,2), sign Int8 -- 1 active, -1 deleted ) ENGINE CollapsingMergeTree(sign) ORDER BY order_id; -- Insert order INSERT INTO orders VALUES (123, 456, 99.99, 1); -- Delete by inserting with sign -1 INSERT INTO orders VALUES (123, 456, 99.99, -1); -- Query collapses 1 and -1 pairs SELECT order_id, sum(total * sign) as total FROM orders GROUP BY order_id HAVING sum(sign) 0;关键点在于删除动作本身是普通 INSERT成本与一次插入完全相同不产生任何 part 重写查询时用sum(total * sign)聚合抵消配合HAVING sum(sign) 0过滤掉已删除行。代价是删除的行会继续占用存储直到后台合并真正将1/-1对物理清除。Langfuse 的实践is_deleted标记 ReplacingMergeTreeLangfuse 没有照搬sign列而是采用同构思路的变体is_deleted标记列 ReplacingMergeTree 版本列。查看 Langfuse 的 ClickHouse 迁移文件 0001_traces.up.sqlCREATE TABLE traces {CLICKHOUSE_CLUSTER_CLAUSE} ( ... event_ts DateTime64(3), is_deleted UInt8, ... ) ENGINE {CLICKHOUSE_REPLICATION_PREFIX}ReplacingMergeTree(event_ts, is_deleted) Partition by toYYYYMM(timestamp)同样的模式贯穿整个仓库的核心表0002_observations.up.sqlReplacingMergeTree(event_ts, is_deleted)按月toYYYYMM(start_time)分区0003_scores.up.sqlReplacingMergeTree(event_ts, is_deleted)0011_add_blob_storage_file_log.up.sql 与 0024_dataset_run_items.up.sql同样的引擎与标记列。ReplacingMergeTree 的两个参数(event_ts, is_deleted)含义深刻event_ts是版本列合并时保留版本最新的一行is_deleted是删除标记列同版本号时按该列决定保留哪一行。这样软删除就退化成一次携带is_deleted 1的普通插入——与规则文档用插入替代突变的精神完全一致。写入侧同样遵循该约定在 clickhouse.ts 中Langfuse 写入blob_storage_file_log表时显式携带is_deleted: 0读取侧在 query-fragments.ts 中通过e.is_deleted 0过滤已删除行保证业务查询只见活跃数据。方案二轻量删除Lightweight DELETE23.3——偶发删除的首选如果删除频率不高、规模不大规则文档推荐使用 ClickHouse 23.3 引入的轻量删除语法也就是标准的DELETE FROM-- Marks rows, doesnt rewrite immediately DELETE FROM orders WHERE status cancelled; -- Physical deletion happens during normal merges轻量删除的精髓是打标记、不重写执行时只在索引中标记命中行并立即对后续查询隐藏物理空间回收交给后台正常的 merge 过程避免了一整轮 part 重写。它适合偶发性的中等规模删除——比突变便宜得多又比软删除方案简单直接无需改动表结构。Langfuse 的实践trace 删除路径中的轻量 DELETELangfuse 的 trace 删除正是这种模式的工程化样板。在 traces.ts 中deleteTraces先做一次 preflight 计数无命中行则直接跳过随后执行的是带时间边界收敛的轻量 DELETE。更典型的实现在 events.tsconst deleteQuery (table: string) DELETE FROM ${table} WHERE project_id {projectId: String} AND trace_id IN ({traceIds: Array(String)}) AND start_time {minTs: String}::DateTime64(3) AND start_time {maxTs: String}::DateTime64(3) ;这段代码体现了三条值得复用的实战经验先查后删先用SELECT ... LIMIT 1/ count 预检见hasAnyEvent与 preflight 逻辑无数据直接跳过避免空 DELETE范围收敛删除条件同时带上start_time的 min/max 边界把命中范围压缩到最小减少需要标记的 part 数量超时保护通过clickhouseConfigs.request_timeout使用env.LANGFUSE_CLICKHOUSE_DELETION_TIMEOUT_MS配置超时见 events.ts防止大删除长时间占住连接。方案三DROP PARTITION——按分区批量删除的瞬时方案当删除目标是整块旧数据例如按时间维度清理一个月前的数据时最优雅的方式是直接丢弃整个分区。规则文档的对比示例-- Instant deletion of old data ALTER TABLE events DROP PARTITION 202301; -- Much faster than: ALTER TABLE events DELETE WHERE toYYYYMM(timestamp) 202301;DROP PARTITION是元数据级操作只需删除分区的目录引用瞬间完成而等价条件的ALTER TABLE DELETE却要逐 part 重写二者性能差距是数量级的。前提是表必须按删除维度通常是时间设计分区键——这正是分区服务于数据生命周期这一设计原则的体现。Langfuse 的实践按月分区 TTL 生命周期管理Langfuse 的所有核心表都按toYYYYMM(...)按月分区如 traces 按toYYYYMM(timestamp)、observations 按toYYYYMM(start_time)天然为按月 DROP PARTITION或按月 TTL做好了结构准备。更进一步的实践是 TTL在 handleEventPropagationJob.ts 的注释中明确写道Relies on table TTL for partition cleanup instead of explicit DROP PARTITION.——Langfuse 的事件传播表依赖 TTL 自动回收分区数据而非显式执行 DROP PARTITION在 0023_traces_aggregating_merge_trees.up.sql 中聚合合并树表使用TTL toDate(start_time) INTERVAL 7 DAY与INTERVAL 30 DAY分级保留数据。TTL 本质上就是到期自动 DROP 分区/part的托管化表达与手动DROP PARTITION同属生命周期管理但无需应用层定时任务。二者组合的完整策略是按月分区 TTL 自动清理 需要即时清除时手动 DROP PARTITION。删除策略选型速查表规则文档给出的四方案对比表是选型的核心依据完整摘录如下MethodSpeedWhen to UseALTER DELETESlowRare corrections onlyCollapsingMergeTreeFastFrequent soft deletesLightweight DELETEMediumOccasional deletesDROP PARTITIONInstantBulk deletion by partition结合 Langfuse 仓库的工程实践可以进一步细化选型准则纠错类、一次性、命中行少用轻量DELETE FROM如 events.ts 中按 trace_id 时间范围删除高频软删除 / 业务删除用 ReplacingMergeTree is_deleted标记如 0001_traces.up.sql删除即插入整块过期数据按月分区 DROP PARTITION或 TTL如 0023_traces_aggregating_merge_trees.up.sql罕见修正仅在无法用上述方案覆盖时才考虑ALTER TABLE DELETE突变。迁移与部署中的配套约束规避突变的规则在 Langfuse 的迁移流程中还有配套约束写 SQL 时需一并遵守详见 SKILL.md 的 Langfuse-Specific Rules 一节任何会创建突变的 ALTERMATERIALIZE ...、UPDATE、DELETE在集群模式下必须携带{CLICKHOUSE_CLUSTERED_ONLY: SETTINGS mutations_sync 2}确保突变完成后才进入下一个迁移文件mutations_sync不能替代alter_sync前者控制突变何时结束后者控制元数据传播二者用途不同不要在 events 表上使用FINALevents 表设计上不依赖 FINAL 就能读到正确数据使用该关键字反而伤害性能见 SKILL.md 中 Never use FINAL on the events table 一条。这与本文方案一用聚合/标记替代 FINAL的思路一脉相承——对 events 这类按时间流式写入的表Langfuse 刻意避免依赖合并语义将正确性前置到写入侧。总结ALTER TABLE DELETE是 ClickHouse 中代价最高的删除方式应被视作最后手段而非默认选项。Langfuse 仓库用三种互补机制覆盖了全部删除场景ReplacingMergeTree is_deleted标记承接高频软删除traces / observations / scores / dataset_run_items 全部采用该模式轻量 DELETE处理偶发的中等规模删除trace / events 删除路径配合 preflight 预检与时间范围收敛按月分区 TTL / DROP PARTITION负责批量过期数据回收。阅读本仓库的迁移目录canonical与删除相关仓库层代码traces.ts、events.ts即可获得一套可复制的生产级 ClickHouse 数据生命周期设计范本。【免费下载链接】langfuse Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。