选择性 UPDATE/DELETE 最多提速 160 倍,UPSERT 也能翻番——这组数字来自刚发布的 TimescaleDB 2.27,它在写入路径上首次引入了布隆过滤剪枝。原本只用于查询的优化,现在对压缩列存数据的写操作同样生效。但兴奋之余,一个隐藏的坑可能会让升级后的你白高兴一场:布隆过滤器到底有没有在你自己的负载中真正启动,执行计划并不会告诉你答案

要理解这一点,得先弄清机制。TimescaleDB 的 Hypercore 用批次(约一千行)压缩存储数据,对非 segmentby 键的列,每个批次会建一个稀疏布隆过滤器。这个概率结构能回答一个问题:“这个批次里有没有可能包含某列等于 X 的行?”根本不需要去碰压缩后的负载。布隆过滤的价值在于一种不对称性——否定结果是确凿的:如果过滤器说“没有”,值就一定不存在,整批都可以跳过;肯定结果却只是“也许”,解压之后有可能发现白忙一场,这就是假阳性。假阳性的数量,正是判断整套方案是否值回开销的关键。

打开网易新闻 查看精彩图片

在 2.27 之前,一条针对压缩数据的 DELETE … WHERE sensor_id = 'x' 会逐个解压候选批次来检查。现在会先查一次布隆过滤,不可能匹配的批次根本不去解压。省下的工作就是这些被剪掉的解压开销;但如果过滤器与数据匹配度差,你反而是在本来就要做的解压之外,多付了一次布隆检查的代价。

真正让人头疼的是,UPDATE/DELETE 和 UPSERT 两条写入路径上,同名计数器居然命名完全不统一,而官方发布说明里只提了一嘴,并没有解释。执行计划里,DELETE 路径下会显示“Compressed batches filtered”,UPSERT 路径下却叫“batches pruned by bloom”,其实它们是同一个量。同样,“Batches filtered after decompression”就等于 UPSERT 下的“bloom false positives”。如果你在一个会话里先后剖析 UPSERT 和 DELETE,指望看到同一套标签,那是找不到的。

UPSERT 路径的诊断价值更高,因为它还会单独暴露“batches without bloom”——那些根本没有过滤器可用的批次数量。而在 UPDATE/DELETE 路径下,这类批次直接被归入已解压队列,和真正匹配却被解压的批次混在一起,无法区分。不掌握这些计数器的真正含义,光看 EXPLAIN 输出,你很难判断布隆过滤到底是在省力还是在添乱。

更要注意的是,这个版本还藏着两个能在升级后静默导致查询中断的变化,如果没留意,一上线查询就可能失败。本文重点是讲清如何正确读取这些新增的 EXPLAIN 计数器,但这两个问题也需要你在升级前做好检查,别让性能提升被意外中断抵消。