当前位置: 首页 > news >正文

我花了一天时间,拆了一下 OpenTeleDB 的 XStore,到底解决了 PG 的哪根老筋?

这两年数据库圈有点像3年前的云原生圈:“分布式”、“新一代内核”、“重构存储引擎”这些词突然又密集起来了。

前几天刷群,看到有人转了 OpenTeleDB 的开源消息,说是“基于 PostgreSQL 的新一代内核”。说实话,我第一反应是:又一个魔改 PG?

但看到里面提到一个点:原位更新 + Undo 引擎(XStore),我还是没忍住下了源码。 因为这恰好戳中我这些年被 PG 折磨得最狠的痛点:

表膨胀、autovacuum 抽风、性能像心电图一样忽高忽低。

所以这次我没看 PPT,也没看宣传稿,直接跑到机器上拆了半天,想看看它究竟动了 PG 的哪根“老筋”。

一、先说结论:XStore 不是快,而是“稳”

我装的是 OpenTeleDB 的 17.6 内核版。 创建方式很直观:

SELECT relname, amname FROM pg_class c JOIN pg_am a ON c.relam = a.oid WHERE relname = 'test_xstore';

这一步其实就已经很有意思了——它不是 fork 了一套新引擎,而是作为插件挂进去的。 这个思路我很认可:

  • 不绑死 PG 版本
  • 能跟着大版本升级
  • 出问题可以随时回退

像 Citus、openHalo 这些“成功插件化路线”的项目,本质都是这个思路。

二、打开数据目录,我第一次意识到:它真不是换皮

$PGDATA下面,多了一个非常显眼的目录:

drwx------ 2 postgres postgres 4096 Nov 3 20:15 undo

这就是 XStore 的核心:它不是靠多版本链来维护 MVCC,而是靠 Undo 日志回滚。

这点和 Oracle、MySQL InnoDB 的逻辑更像。

也正是它敢说“原位更新”的底气来源。

三、插入测试:它不快,但很“诚实”

我用同样的参数,在同一台机器上跑了两组:

INSERT INTO test_xstore (name, value) SELECT md5(random()::text), (random()*1000)::int FROM generate_series(1,10000000);
INSERT INTO test_heap (name, value) SELECT md5(random()::text), (random()*1000)::int FROM generate_series(1,10000000);

结果是:

写慢了将近一倍。这点我反而觉得真实:因为 XStore 在写数据页的同时,还要写一份 Undo。物理写入翻倍,吞吐下降是必然的。如果一个系统告诉你“原位更新 + Undo 还更快”,那我反而会不太信。

四、创新实验:模拟1千万数据的存储膨胀对比

我设计了一项创新实验:在 1000 万条级别的大数据量下,评估 XStore 与 Heap 表在高频更新下的空间膨胀、索引稳定性以及查询性能表现。该实验主要有两个创新点:

大规模数据模拟

  1. 使用generate_series(1,10000000)生成 1000 万条数据,保证数据量级对存储膨胀影响明显。
  2. 初始数据包括idnamevalueupdated_at四列,与前期实验一致,但数据量增加十倍,以模拟真实大规模 OLTP 系统负载。

多维度空间分析

  1. 不仅监控表总大小,还分别统计索引占用和 TOAST 表空间。
  2. 每轮更新后,通过pg_relation_sizepg_total_relation_sizepg_indexes_size获取精细化指标。
  3. 引入可视化趋势分析,绘制表空间增长曲线,以直观展示 XStore 与 Heap 的差异。

4.1实验设计

表结构

CREATE TABLE xstore_large ( id SERIAL PRIMARY KEY, name TEXT, value INT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) USING XSTORE; CREATE TABLE heap_large ( id SERIAL PRIMARY KEY, name TEXT, value INT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

初始化 1000 万条数据

INSERT INTO xstore_large (name, value) SELECT 'name_' || g, g FROM generate_series(1, 10000000) AS g; INSERT INTO heap_large (name, value) SELECT 'name_' || g, g FROM generate_series(1, 10000000) AS g;

先对现在存入1000w数据的空间监控与记录一下如下。

xstore_total | xstore_index | heap_total | heap_index --------------+--------------+------------+------------ 985 MB | 388 MB | 789 MB | 214 MB

多轮全表更新

  • 连续 5 轮更新,每轮更新valueupdated_at,模拟写入密集场景:
UPDATE xstore_large SET value = value + 1, updated_at = CURRENT_TIMESTAMP; UPDATE heap_large SET value = value + 1, updated_at = CURRENT_TIMESTAMP;

空间监控与记录

SELECT pg_size_pretty(pg_total_relation_size('xstore_large')) AS xstore_total, pg_size_pretty(pg_indexes_size('xstore_large')) AS xstore_index, pg_size_pretty(pg_total_relation_size('heap_large')) AS heap_total, pg_size_pretty(pg_indexes_size('heap_large')) AS heap_index;

第一轮:

xstore_total | xstore_index | heap_total | heap_index --------------+--------------+------------+------------ 985 MB | 388 MB | 1578 MB | 428 MB

第五轮:

xstore_total | xstore_index | heap_total | heap_index --------------+--------------+------------+------------ 985 MB | 388 MB | 1628 MB | 428 MB

4.2千万数据更新膨胀可视化

五、实验结论

这组 1000 万级数据 + 多轮全表更新的实验,其实把 PG 传统 Heap 表的“老问题”放大得非常清楚。

最核心的对比结果只有一句话:

XStore 的空间是线性的、可预测的;Heap 表的空间是失控的、不可预测的。

具体来看:
1. 表空间膨胀
a. Heap 表在第一次更新后,表体空间直接翻倍,从 789MB 飙到 1578MB。
b. 之后每一轮更新,虽然增长幅度趋缓,但空间再也回不到初始状态。
c. XStore 从头到尾不变: 985MB → 985MB → 985MB
2. 索引体积稳定性
a. Heap 表索引从 214MB 膨胀到 428MB,且在后续更新中保持“高位横盘”。
b. XStore 的索引尺寸始终维持在 388MB 左右,没有明显漂移。
3. 更新行为本质差异
a. Heap:每一次 UPDATE,本质都是 DELETE + INSERT → 老版本残留 → 表膨胀 → 索引碎片 → autovacuum 压力。
b. XStore:真正的原位更新 → 历史版本进 Undo → 主表物理页不变 → 无膨胀。
4. 长期可运维性
a. 在 Heap 表上,如果你不 VACUUM,它一定会慢; 如果你 VACUUM,系统一定会抖。
b. 在 XStore 上,这两件事都不再是必选项。
这意味着什么?

它不是让你飞起来,而是让你不再塌方

六、我的心得

说实话,这几年我已经对“新一代数据库内核”这类说法有点免疫了。大多数项目,要么是在 PG 上糊一层分布式壳; 要么就是换个名字,重新卖一遍 MVCC。而 XStore 给我的感觉不一样。它没有试图掩盖代价。写入更慢, IO 更多,架构更复杂。

但它正面承认了一个事实:

PostgreSQL 的 MVCC,在高频更新场景下已经接近物理极限。

这不是参数调优能解决的事,也不是加机器能扛住的事,而是存储模型本身的问题。这些年我见过太多系统:白天 QPS 很稳,半夜 autovacuum 开始清垃圾,延迟突然拉长,业务报警,DBA 开始手工 VACUUM / REINDEX / CLUSTER,第二天继续循环。

这不是运维水平的问题,而是模型在和现实硬扛。XStore 让我第一次意识到:原来 PG 也可以选择不走这条老路。它没有追求“更快”,而是选择了一个更难、但更稳的方向:

  • 用 Undo 换空间可控
  • 用写放大换性能平滑
  • 用工程复杂度换系统长期可预期性

如果你是写多、更新密集型 OLTP 系统,如果你被表膨胀、索引碎片、autovacuum 抽风折磨过,那你会和我一样—不一定立刻用它,但你会开始认真看它。这大概就是我这次拆源码、跑实验,最大的收获。

http://www.jsqmd.com/news/342788/

相关文章:

  • AI代理:AI原生应用领域的关键驱动力
  • 使用darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74训练图片是怎么生成权重文件的,怎么定义权重文件名?
  • 26年人形机器人谁领跑 智平方依托GOVLA大模型+近5亿订单跻身十强
  • AI产品经理核心能力图谱:不只是写Prompt,这些能力才是关键!
  • Plotly + Dash:构建交互式数据仪表盘的艺术与实战
  • 进程与线程:8核CPU究竟能创建多少?
  • 实测中石化加油卡回收平台,京顺回收闲置卡券变现优选 - 京顺回收
  • Kmesh-Waypoint 深度解析:Kmesh 服务网格的七层流量管理引擎
  • 模型服务化这件事:从 Batch 到 Stream,不只是改个部署方式那么简单
  • 提示工程架构师工具选型:破解Agentic AI技术挑战的6款必备开源框架
  • AI大模型产品经理修炼手册 | 七阶段学习路线,收藏不迷路
  • Itinerary(行程单)
  • LLM支持的AI Agent实体链接技术
  • 从不会AI到转型产品经理:一位35+研发的100天真实记录
  • 人机共创在AI原生应用中的发展路径探索
  • 10年产品总监揭秘:AI产品经理必备的6大核心能力与转型指南
  • SentGraph:大模型多跳问答的终极解决方案,降低token消耗69%的秘诀
  • 【领域知识】一个休闲游戏产品(安卓和iOS)从0到1
  • 【投稿指南】2026年3-4月人工智能学术会议信息汇总 | 人工智能领域国际学术会议征稿信息速览 | AI人必备,一键速览AI会议冲刺表,7天录用+稳EI检索!
  • 大数据Kappa架构:实现数据实时洞察的架构选择
  • AI上下文工程知识图谱迭代难?提示工程架构师的优化方法
  • 深入了解AI原生应用领域思维框架,把握行业趋势
  • 手机防盗器UI设计
  • 智能体来了:传统行业的新心脏
  • 2026 年深圳 APP 定制开发公司权威推荐:谁真正具备交付能力? - 品牌权威排行榜
  • 【2026年】AI大模型应用开发学习路线:零基础到高薪开发者的进阶指南
  • OpenClaw 开源项目深度技术解析:从 “主动式智能助手“ 到 “数字员工“ 的技术跃迁
  • Async和AsyncTask
  • 全网爆火的 Agent Skills:拆解智能体的核心能力,从概念炒作到落地实践
  • dnslog自建记录