OpenTeleDB 數據庫線上征文活動優秀作品來襲!本篇為精選文章,分享實戰經驗與技術感悟,敬請閱讀。
這兩年數據庫圈有點像 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------2postgrespostgres4096Nov320:15undo這就是 XStore 的核心: 它不是靠多版本鏈來維護 MVCC,而是靠 Undo 日志回滾。
這點和 Oracle、MySQL InnoDB 的邏輯更像。
也正是它敢說 "原位更新" 的底氣來源。
三、插入測試:它不快,但很 "誠實"
我用同樣的參數,在同一臺機器上跑了兩組:
INSERTINTO test_xstore (name, value) SELECTmd5(random()::text), (random()*1000)::int FROM generate_series(1,10000000);INSERTINTO test_heap (name, value) SELECTmd5(random()::text), (random()*1000)::int FROM generate_series(1,10000000); ![]()
結果是:
![]()
寫慢了將近一倍。這點我反而覺得真實:因為 XStore 在寫數據頁的同時,還要寫一份 Undo。物理寫入翻倍,吞吐下降是必然的。如果一個系統告訴你 "原位更新 + Undo 還更快",那我反而會不太信。
四、創新實驗:模擬 1 千萬數據的存儲膨脹對比
我設計了一項創新實驗:在 1000 萬條級別的大數據量下,評估 XStore 與 Heap 表在高頻更新下的空間膨脹、索引穩定性以及查詢性能表現。該實驗主要有兩個創新點:
大規模數據模擬
使用
generate_series(1,10000000)生成 1000 萬條數據,保證數據量級對存儲膨脹影響明顯。初始數據包括
id、name、value和updated_at四列,與前期實驗一致,但數據量增加十倍,以模擬真實大規模 OLTP 系統負載。
多維度空間分析
不僅監控表總大小,還分別統計索引占用和 TOAST 表空間。
每輪更新后,通過
pg_relation_size、pg_total_relation_size和pg_indexes_size獲取精細化指標。引入 可視化趨勢分析,繪制表空間增長曲線,以直觀展示 XStore 與 Heap 的差異。
![]()
4.1 實驗設計
表結構
CREATETABLE xstore_large ( idSERIAL PRIMARY KEY, nameTEXT, valueINT, updated_at TIMESTAMPDEFAULTCURRENT_TIMESTAMP ) USING XSTORE; CREATETABLE heap_large ( idSERIAL PRIMARY KEY, nameTEXT, valueINT, updated_at TIMESTAMPDEFAULTCURRENT_TIMESTAMP ); ![]()
初始化 1000 萬條數據
INSERTINTO xstore_large (name, value) SELECT'name_' || g, g FROM generate_series(1, 10000000) AS g; INSERTINTO heap_large (name, value) SELECT'name_' || g, g FROM generate_series(1, 10000000) AS g; ![]()
先對現在存入 1000w 數據的空間監控與記錄一下如下。
![]()
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; 985 MB | 388 MB | 789 MB | 214 MB多輪全表更新
連續 5 輪更新,每輪更新
value和updated_at,模擬寫入密集場景:
UPDATE xstore_large SETvalue = value + 1, updated_at = CURRENT_TIMESTAMP; UPDATE heap_large SETvalue = 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;第一輪:
![]()
985 MB | 388 MB | 1578 MB | 428 MB第五輪:
![]()
985 MB | 388 MB | 1628 MB | 428 MB4.2 千萬數據更新膨脹可視化
![]()
![]()
五、實驗結論
這組 1000 萬級數據 + 多輪全表更新的實驗,其實把 PG 傳統 Heap 表的 "老問題" 放大得非常清楚。
最核心的對比結果只有一句話:
XStore 的空間是線性的、可預測的;Heap 表的空間是失控的、不可預測的。
具體來看:
表空間膨脹
a. Heap 表在第一次更新后,表體空間直接翻倍,從 789MB 飆到 1578MB。
b. 之后每一輪更新,雖然增長幅度趨緩,但空間再也回不到初始狀態。
c. XStore 從頭到尾不變: 985MB → 985MB → 985MB
索引體積穩定性
a. Heap 表索引從 214MB 膨脹到 428MB,且在后續更新中保持 "高位橫盤"。
b. XStore 的索引尺寸始終維持在 388MB 左右,沒有明顯漂移。
更新行為本質差異
a. Heap:每一次 UPDATE,本質都是 DELETE + INSERT → 老版本殘留 → 表膨脹 → 索引碎片 → autovacuum 壓力。
b. XStore:真正的原位更新 → 歷史版本進 Undo → 主表物理頁不變 → 無膨脹。
長期可運維性
a. 在 Heap 表上,如果你不 VACUUM,它一定會慢; 如果你 VACUUM,系統一定會抖。
b. 在 XStore 上,這兩件事都不再是必選項。
這意味著什么?
它不是讓你飛起來,而是讓你不再塌方。
六、我的心得
說實話,這幾年我已經對 "新一代數據庫內核" 這類說法有點免疫了。大多數項目,要么是在 PG 上糊一層分布式殼; 要么就是換個名字,重新賣一遍 MVCC。而 XStore 給我的感覺不一樣。它沒有試圖掩蓋代價。寫入更慢, IO 更多,架構更復雜。
但它正面承認了一個事實:
PostgreSQL 的 MVCC,在高頻更新場景下已經接近物理極限。
這不是參數調優能解決的事,也不是加機器能扛住的事,而是存儲模型本身的問題。這些年我見過太多系統:白天 QPS 很穩,半夜 autovacuum 開始清垃圾,延遲突然拉長,業務報警,DBA 開始手工 VACUUM / REINDEX / CLUSTER,第二天繼續循環。
這不是運維水平的問題,而是模型在和現實硬扛。XStore 讓我第一次意識到:原來 PG 也可以選擇不走這條老路。它沒有追求 "更快",而是選擇了一個更難、但更穩的方向:
用 Undo 換空間可控
用寫放大換性能平滑
用工程復雜度換系統長期可預期性
如果你是寫多、更新密集型 OLTP 系統,如果你被表膨脹、索引碎片、autovacuum 抽風折磨過,那你會和我一樣 --- 不一定立刻用它,但你會開始認真看它。這大概就是我這次拆源碼、跑實驗,最大的收獲。
作者:難忘兄
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.