尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
TimescaleDB 压缩块整理(compact_chunk):重叠压缩批次的检测、合并与源码实现解析
TimescaleDB 压缩块整理compact_chunk重叠压缩批次的检测、合并与源码实现解析【免费下载链接】timescaledbA time-series database for high-performance real-time analytics packaged as a Postgres extension项目地址: https://gitcode.com/gh_mirrors/ti/timescaledb导读本文围绕 TimescaleDB 的压缩块整理compact chunk机制展开深入讲解_timescaledb_functions.compact_chunk如何发现并合并同一压缩块chunk内发生重叠的压缩批次batch同时保持正确排序、不触碰健康批次。读完本文你将掌握重叠检测依赖的 firstlast 稀疏元数据原理、三阶段工作流FIND → RECOMPRESS → VERIFY、八种典型压缩/批次配置下的行为、以及如何通过 SQL 函数与压缩整理策略compaction policy在实战中调用它。1. 什么是 compact_chunk只修乱序批次不重排一切在 TimescaleDB 的列式压缩存储中数据以**压缩批次batch为单位组织每个批次内部按compress_orderby指定的列排序并对应一条索引记录。正常写入的压缩块中相邻批次的排序键范围应当是连续的、互不重叠的。但当发生乱序写入、compress_chunk_time_interval合并压缩、或对已压缩数据执行删除/更新等操作后可能产生相邻批次排序键范围互相覆盖overlap**的情况即乱序批次。compact_chunk正是针对这一问题的整理工具。根据 tsl/src/compression/COMPACT_CHUNK.md 的定义它合并同一 chunk 内重叠的压缩批次只处理需要修复的批次——排序正确的批次原样保留绝不无谓解压重写它只针对已完全压缩、且状态含UNORDERED的 chunk 生效sql/policy_internal.sql 中策略的筛选条件也印证了这一点。其 SQL 入口定义在 sql/maintenance_utils.sqlCREATE OR REPLACE FUNCTION _timescaledb_functions.compact_chunk( chunk REGCLASS, max_batches INTEGER DEFAULT 0 ) RETURNS REGCLASS AS MODULE_PATHNAME, ts_compact_chunk LANGUAGE C STRICT VOLATILE;底层 C 实现位于 tsl/src/compression/recompress.c 的tsl_compact_chunk。该函数对输入做了严格校验必须先启用压缩特性ts_feature_flag_check(FEATURE_HYPERTABLE_COMPRESSION)不支持REPEATABLE READ/SERIALIZABLE隔离级别因为整理过程依赖命令计数器推进与新鲜快照验证见源码第 261-267 行chunk 必须已压缩且**不是部分压缩partial**状态否则直接报错max_batches必须大于等于 0它限制一次整理最多解压/合并的批次数量用于将大块整理拆分为多次小事务执行。1.1 与列式压缩策略compaction policy的关系compact_chunk也是自动压缩整理策略的底层执行器。在 sql/policy_internal.sql 中策略支持以下配置项配置项类型默认值含义verbose_logBOOLEANFALSE是否输出详细日志max_chunksINTEGER0单次运行最多处理的 chunk 数0 表示不限制max_batchesINTEGER0传给compact_chunk的批次上限0 表示不限制inactive_forINTERVALNULL仅整理空闲窗口内无写入的 chunk避免反复整理仍在接收乱序数据的块NULL表示关闭该门槛策略只会选择状态为UNORDERED且非PARTIAL、非FROZEN的 chunk 调用compact_chunksql/policy_internal.sql并对单个 chunk 的失败捕获异常后继续第 81-91 行每处理一个 chunk 提交一次事务。2. 核心原理用 firstlast 稀疏元数据判断重叠无需解压重叠检测是整个机制的关键设计它完全不需要解压任何批次而是直接读取压缩块索引中的firstlast 稀疏元数据sparse metadata。2.1 firstlast 元数据存了什么对于每个压缩批次firstlast 元数据精确记录了该批次首行与末行在每个orderby列上的真实值。这是压缩写入时由 tsl/src/compression/batch_metadata_builder_firstlast.c 维护的。由于元数据持有的是每个 orderby 列的真实边界行因此即使是多列 orderby例如orderbydevice,time也能在不解压的情况下完成比较判断规则是当前批次的首行排序早于前一批次的末行则两个相邻批次重叠。实现上compact_chunk_impl 会先逐列检查每个 orderby 列是否具备 firstlast 稀疏索引orderby_sparse_kind(...) ! ORDERBY_SPARSE_FIRSTLAST时给出 WARNING 并跳过整理并提示重新压缩该 chunk 以补齐 firstlast 元数据——这说明只有老式稀疏索引配置如 bloom1/minmax的压缩块无法被整理必须先重压缩升级。2.2 扫描状态机扫描状态由CompactChunkScanState结构维护recompress.c它保存previous_tid/first_overlap_tid前一批次与首个重叠批次的 TID供后续按 TID 精确抓取合并seg_values/seg_isnull当前批次的 segmentby 键值用于识别段组切换不同 segment 之间互不比较curr_first/curr_last当前批次的首行/末行 orderby 元组直接从索引读出max_last/max_last_isnull已处理批次中最大的末行元组副本持拷贝避免随索引扫描推进而失效。其中max_last的使用值得注意重叠比较的对象并非紧邻前一批次而是当前段组内此前所有批次中末行最大的那个这保证了对多批次连锁重叠的正确判定。3. 三阶段工作流FIND → RECOMPRESS → VERIFY原文档给出了整理的整体流程Phase 1: FIND Phase 2: RECOMPRESS Phase 3: VERIFY ┌──────────────┐ ┌──────────────────┐ ┌────────────────┐ │ Index scan │──────▶│ Decompressmerge │─────▶│ Re-scan with │ │ Stop at │ │ overlapping │ │ fresh snapshot │ │ first issue │ │ batches, continue│ │ Clear UNORDERED│ └──────────────┘ │ scanning for more│ └────────────────┘ └──────────────────┘3.1 Phase 1FIND —— 索引扫描遇首个问题即停compact_chunk_find_overlapping_batchesrecompress.c沿压缩块索引正向扫描对每个批次调用read_batch_firstlast读取边界元组段组内首个批次或check_changed_group检测到 segmentby 变化时的新组首个批次只记录为前驱并重置组内max_last第 1161-1176 行一旦batches_overlap_firstlast判定当前批次与组内最大末行重叠立刻停止扫描记录first_overlap_tid并返回true第 1178-1187 行无重叠则把当前批次作为新的前驱并更新max_last继续扫描。这种首遇即停的设计让 FIND 阶段开销极小——一个健康的 chunk 只需一次顺序索引扫描即可确认无需整理。3.2 Phase 2RECOMPRESS —— 按 TID 抓取、解压合并、继续吸收compact_chunk_recompress_overlapping_batchesrecompress.c在 FIND 结果的基础上执行用table_index_fetch_tuple按 TID 精确抓取首个重叠对的两个批次first_overlap_tid与previous_tid解压进共享的tuplesortdecompress_batch_to_tuplesortCommandCounterIncrement()使删除对当前事务可见主扫描循环从 FIND 停下的位置继续把后续仍在同一段组内、与合并结果仍重叠的批次继续吸收进合并组段组结束时将tuplesort中收集的所有行按 orderby 排序键含 NULLS FIRST/LAST 设置重新排序再用RowCompressor重新压缩成新的、排序正确的批次排序初始化见 recompress.ctuplesort_begin_heap使用maintenance_work_mem作为内存预算。max_batches在此阶段控制解压的批次数上限processed_batches计数从而把单个事务的工作量控制在可预期范围内。3.3 Phase 3VERIFY —— 新鲜快照复扫干净则清除 UNORDERED合并完成后进入验证阶段recompress.c通过ConditionalLockRelation(compressed_chunk_rel, ExclusiveLock)尝试性获取排他锁——拿不到说明有并发事务跳过状态清理不阻塞必须注册一个新鲜快照重新扫描因为重压缩过程中发生了CommandCounterIncrement原快照仍能看到被删除的旧批次、却看不到新插入的批次只有新快照才能反映整理后的真实状态源码注释明确说明了这一点复扫确认不再有任何重叠后调用ts_chunk_clear_status清除 chunk 的COMPRESSED_UNORDERED状态并CacheInvalidateRelcacheByRelid使相关计划失效若仍发现重叠例如并发写入引入了新乱序则保留UNORDERED状态交由下一次整理处理。3.4 并发安全与锁策略compact_chunk_implrecompress.c采用克制的锁策略压缩块ShareUpdateExclusiveLock主要用于阻止 DDL未压缩块仅AccessShareLock只读打开整理开始前用GetLockConflicts探测是否存在与ExclusiveLock冲突的持锁者并发 DML 持有RowExclusiveLock若存在则直接跳过本次整理并发出 WARNING而不是阻塞等待整理完成后仅以ConditionalLockRelation方式升级锁来清理状态进一步避免长时间阻塞写入。4. 八种典型场景行为详解以下行为均继承自 COMPACT_CHUNK.md 的场景描述并结合源码确认了判定逻辑。4.1 场景 1无重叠no-op只清状态三个批次1..100、101..200、201..300边界严格衔接、互不覆盖┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ 1..100 │ │101..200│ │201..300│ ───▶ │ 1..100 │ │101..200│ │201..300│ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ (unchanged, UNORDERED cleared)FIND 阶段全程无重叠命中found_overlaps false不进入 RECOMPRESS随后 VERIFY 复扫通过直接清除UNORDERED状态。数据零拷贝、零解压这是整理操作的最优路径。4.2 场景 2存在重叠批次三个批次中第二个50..150与第一个1..100的50..100区间重叠也与第三个201..300无覆盖关系┌──────────┐ ┌───────┐┌───────┐┌───────┐┌──┐┌────────┐ │ 1..100 │ │ 1..50 ││51..100││101 ││ ││201..300│ └──────────┘ │ ││ ││ ..150 ││… │└────────┘ ┌──────────┐ ───▶ └───────┘└───────┘└───────┘└──┘ │ 50..150 │ ◄────── merged re-sorted ──► ◄ kept ► └──────────┘ ┌────────┐ │201..300│ └────────┘前两个批次被解压合并、按 orderby 重新排序后压缩为一个批次图上示意其内部行1..150重新分段存储201..300未受波及、原样保留。这正是只动有问题的批次原则的体现。4.3 场景 3segmentby 维度——按段独立处理重叠判断严格限定在同一 segmentby 组内check_changed_group检测到键值变化即重置组内max_last不同段互不影响d1: ┌──────┐ ┌───────┐ d1: ┌──────────────┐ │1..100│ │50..200│ ──▶ │ 1..200 merged│ └──────┘ └───────┘ └──────────────┘ d2: ┌──────┐ ┌───────┐ d2: ┌──────────────┐ │1..100│ │50..200│ ──▶ │ 1..200 merged│ └──────┘ └───────┘ └──────────────┘注意每个段内的合并是独立并行进行的d1的两批次合为一组d2的两批次合为一组两组互不干扰每个段组结束时各自触发一次吸收 → 排序 → 重压缩。4.4 场景 4DESC 倒序 orderby当orderbytime DESC时批次内部按时间从大到小排列重叠判定同样遵循排序语义orderbytime DESC max◄────────────────────►min ┌──────────┐ ┌──────────────────┐ │ 200..100 │ │ 200..........100 │ └──────────┘ ──▶ │ merged │ ┌──────────┐ └──────────────────┘ │ 150..50 │ └──────────┘两个批次都呈降序排列150..50的头部与200..100的尾部交叉100 150在降序语义下即重叠合并后重新按DESC排序为一个批次。比较方向由 orderby 列的排序操作符自动处理batches_overlap_firstlast无需感知方向差异。4.5 场景 5多列 orderby——边界并列时的次级列裁决当首列col1的 first/last 值并列tie时直接取元数据中的次级列继续比较全程零解压orderbydevice,time Both batches tie on device (firstd2, lastd2) Batch 1 last row: (d2, 08:20) ◄─ from last metadata Batch 2 first row: (d2, 08:21) ◄─ from first metadata 08:20 08:21 → no overlap ✓ Batch 1 last row: (d2, 08:20) Batch 2 first row: (d2, 08:11) 08:20 08:11 → OVERLAP → merge两组对比展示了并列裁决设备同为d2时用时间列裁决——前一批次末行时间早于后一批次首行时间则不重叠反之重叠合并。由于 firstlast 元数据保存的是每一列的边界行多列比较所需的全部信息都已具备。4.6 场景 6首列含混合 NULL 的批次与邻批重叠当 orderby 首列允许 NULL 且批次内同时含有 NULL 与非 NULL 值时其边界行是 NULL。在NULLS LAST语义下NULL 末行排在后续非 NULL 批次之后从而形成重叠orderbyvalue NULLS LAST last row of batch 1 is NULL, sorts after batch 2 ┌─────────────────────┐ ┌──────────┐ ┌────────────────────────────────┐ │ 1001..1800, NULL×200│ │1801..2800│ ──▶ │ 1001..2800 re-sorted, NULL×200 │ └─────────────────────┘ └──────────┘ └────────────────────────────────┘ first1001, lastNULL ──▶ overlap merged, NULLs at end (NULLS LAST)合并后重新排序NULL 行按NULLS LAST规则自然沉降到批次末尾。原文档特别强调一个含混合 NULL 但无邻居与之重叠的批次本身已是有序的会被原样保留——即混合 NULL 本身不构成病态只有与邻批产生排序交叉才触发整理。4.7 场景 7重叠合并时保留 NULL 的排序位置对可空首列的重叠批次合并重排序会把 NULL 行保持在正确的有序位置orderbyvalue NULLS LAST ┌──────────────────┐ ┌──────────────────────────┐ │ 1..400, NULL×100 │ ──▶ │ 1..699 re-sorted, NULL×100│ └──────────────────┘ └──────────────────────────┘ ┌──────────┐ overlap NULLs kept at end (NULLS LAST) │ 200..699 │ on 200..400 └──────────┘两个批次在200..400区间重叠合并后得到1..699的有序范围100个 NULL 行仍被保留且按NULLS LAST位于末尾。这一行为由 tuplesort 的排序键设置保证——源码在 recompress.c 的注释中明确说明tuplesort 按包含 NULLS FIRST/LAST 设置的 orderby 键排序NULL 行自动落位。4.8 场景 8次级列 NULL 出现在边界并列处边界比较遵循该列自身的排序设置——NULL 在NULLS LAST下列比较时与普通值无异即大于一切非 NULL 值orderbytime, value NULLS LAST Batch 1 last row: (08:20, NULL) CORRECT: NULL with NULLS LAST Batch 2 first row: (08:20, 1001) means NULL 1001 → OVERLAP → merge ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │ ..., (08:20,NULL)│ │(08:20,1001), ... │ ──▶ │ merged correctly sorted│ └──────────────────┘ └──────────────────┘ └──────────────────────────┘时间列并列于08:20时次级列value登场前一批次末行值为 NULLNULLS LAST下视为最大后一批次首行为1001NULL 1001判定重叠并合并。此场景说明 NULL 处理不是特判分支而是统一由列排序语义排序操作符 nulls_first 标志自然推导保证边界裁决与查询排序完全一致。5. 何时使用与注意事项总结5.1 适用场景乱序写入导致压缩块内批次范围交叉、查询需要额外合并开销时compress_chunk_time_interval合并压缩后产生的非严格有序批次参见 tsl/src/compression/README.md 关于时间维度非 orderby 首列时合并会产生乱序、需要立即重压缩的说明通过压缩整理策略自动维护对仍在接收乱序数据的 chunk 设置inactive_for窗口避免反复整理sql/policy_internal.sql。5.2 前提与限制只对已完全压缩、状态含UNORDERED的 chunk生效未压缩或 PARTIAL 状态会直接报错recompress.c要求所有 orderby 列都具备firstlast 稀疏索引否则跳过整理并提示先重压缩升级recompress.c不支持REPEATABLE READ/SERIALIZABLE隔离级别recompress.c检测到并发 DML 时主动跳过而非阻塞通过max_batches可控制单次事务的工作量适合拆分为多次小事务在后台执行整理本身不会改变压缩算法的选择——合并重压缩仍遵循 chunk 的既有compress_orderby/compress_segmentby设置排序键与 NULL 语义在 compress_chunk_populate_recompress_ctx 中从压缩设置重建。6. 相关代码索引关注点位置功能设计文档tsl/src/compression/COMPACT_CHUNK.mdSQL 函数入口sql/maintenance_utils.sql压缩整理策略自动调用sql/policy_internal.sqlC 实现tsl_compact_chunk/compact_chunk_impltsl/src/compression/recompress.c、recompress.cC 实现FIND 阶段tsl/src/compression/recompress.cC 实现RECOMPRESS 阶段tsl/src/compression/recompress.cfirstlast 稀疏元数据构建tsl/src/compression/batch_metadata_builder_firstlast.c压缩算法总览tsl/src/compression/README.md总而言之compact_chunk是 TimescaleDB 压缩存储中以最小代价恢复有序性的关键机制它用 firstlast 稀疏元数据把重叠检测做到零解压用首遇即停 按 TID 合并 新鲜快照复扫的三阶段流程把整理成本控制在只触及问题批次并通过克制的锁策略与max_batches上限保证与在线写入的和平共处。【免费下载链接】timescaledbA time-series database for high-performance real-time analytics packaged as a Postgres extension项目地址: https://gitcode.com/gh_mirrors/ti/timescaledb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

JCSprout 源码实战:从零手写 LRU 缓存淘汰策略(三套实现演进)

JCSprout 源码实战:从零手写 LRU 缓存淘汰策略(三套实现演进)

文档教程后端 【免费下载链接】JCSprout 👨‍🎓 Java Core Sprout : basic, concurrent, algorithm 项目地址: https://gitcode.com/gh_mirrors/jc/JCSprout 点击查看 免费下载 LRU(Least Recently Used,最近最少使用…

📅 2026/9/20 23:31:47
AssetRipper 免费 Unity 资产提取工具:新手上手指南

AssetRipper 免费 Unity 资产提取工具:新手上手指南

AssetRipper 免费 Unity 资产提取工具:新手上手指南 【免费下载链接】AssetRipper GUI application to analyze game files 项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper AssetRipper 是一款跨平台 Unity 资产提取工具,能把 .a…

📅 2026/9/20 23:26:47
Wox AI Skills 实战指南:用 `wox-plugin-creator` 让 Agent 高效开发插件

Wox AI Skills 实战指南:用 `wox-plugin-creator` 让 Agent 高效开发插件

Wox AI Skills 实战指南:用 wox-plugin-creator 让 Agent 高效开发插件 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 本篇指南讲解 Wox 为插件开发内置的 AI Skill 体系,…

📅 2026/9/20 23:26:47
MORE NEWS

更多资讯

📰

GraalVM Native Image 静态分析报告(Points-to Analysis Reports)完全指南:调用树、对象树与可达性追踪

GraalVM Native Image 静态分析报告(Points-to Analysis Reports)完全指南:调用树、对象树与可达性追踪 【免费下载链接】graal GraalVM compiles applications into native executables that start instantly, scale fast, and use fewer co…

📰

AMS 2700F标准解读:不锈钢钝化工艺要点与实施指南

简介:SAE AMS 2700F中文版是不锈钢钝化处理的技术标准,专门面向航空航天、汽车制造及医疗器械等领域的工艺工程师、质量检验人员与生产管理者。标准内容涵盖可接受材料类型、清洗脱脂等预处理要求、钝化液组成与温度时间参数、外观检查与盐雾试验等检验方…

📰

TiXL 浮点运算算子库 Lib.numbers.float 完全指南:44 个算子的参数详解、源码原理与实战串联

TiXL 浮点运算算子库 Lib.numbers.float 完全指南:44 个算子的参数详解、源码原理与实战串联 【免费下载链接】t3 TiXL is an open source software to create realtime motion graphics. 项目地址: https://gitcode.com/GitHub_Trending/t3/t3 本文以 TiXL&…

📰

大众TL52625前端框架材料要求详解:从性能测试到落地执行

简介:大众汽车集团技术标准TL 52625英文版聚焦前端框架(mounting bracket)材料要求,面向汽车零部件供应商、材料与质量工程师,用于规范热塑性塑料及混合技术(如PP GMT、长玻纤增强PP、PP注射成型LFT、聚酰胺…

📰

OneUptime 自定义探针(Custom Probe)部署实战:私网监控、代理配置与断连排障全指南

可观测性后端运维前端云原生微服务AI Agent 【免费下载链接】oneuptime Complete open-source monitoring and observability platform. 项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime 点击查看 免费下载 自定义探针(Custom Probe&#…

📰

Swagger UI Schema 校验与错误标记实战

Swagger UI Schema 校验与错误标记实战 【免费下载链接】swagger-ui Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API. 项目地址: https://gitcode.com/GitHub_Trending/s…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬