OpenTeleDB 數(shù)據(jù)庫線上征文活動優(yōu)秀作品來襲!本篇為精選文章,分享實戰(zhàn)經(jīng)驗與技術(shù)感悟,敬請閱讀。
這兩年數(shù)據(jù)庫圈有點像 3 年前的云原生圈:"分布式"、"新一代內(nèi)核"、"重構(gòu)存儲引擎" 這些詞突然又密集起來了。
前幾天刷群,看到有人轉(zhuǎn)了 OpenTeleDB 的開源消息,說是 "基于 PostgreSQL 的新一代內(nèi)核"。說實話,我第一反應(yīng)是:又一個魔改 PG?
但看到里面提到一個點:原位更新 + Undo 引擎(XStore),我還是沒忍住下了源碼。 因為這恰好戳中我這些年被 PG 折磨得最狠的痛點:
表膨脹、autovacuum 抽風(fēng)、性能像心電圖一樣忽高忽低。
所以這次我沒看 PPT,也沒看宣傳稿,直接跑到機器上拆了半天,想看看它究竟動了 PG 的哪根 "老筋"。
一、先說結(jié)論:XStore 不是快,而是 "穩(wěn)"
![]()
我裝的是 OpenTeleDB 的 17.6 內(nèi)核版。 創(chuàng)建方式很直觀:
SELECT relname, amname FROM pg_class c JOIN pg_am a ON c.relam = a.oid WHERE relname = 'test_xstore'; ![]()
這一步其實就已經(jīng)很有意思了 ------ 它不是 fork 了一套新引擎,而是作為插件掛進(jìn)去的。 這個思路我很認(rèn)可:
不綁死 PG 版本
能跟著大版本升級
出問題可以隨時回退
像 Citus、openHalo 這些 "成功插件化路線" 的項目,本質(zhì)都是這個思路。
![]()
二、打開數(shù)據(jù)目錄,我第一次意識到:它真不是換皮
在 $PGDATA 下面,多了一個非常顯眼的目錄:
drwx------2postgrespostgres4096Nov320:15undo這就是 XStore 的核心: 它不是靠多版本鏈來維護(hù) MVCC,而是靠 Undo 日志回滾。
這點和 Oracle、MySQL InnoDB 的邏輯更像。
也正是它敢說 "原位更新" 的底氣來源。
三、插入測試:它不快,但很 "誠實"
我用同樣的參數(shù),在同一臺機器上跑了兩組:
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); ![]()
結(jié)果是:
![]()
寫慢了將近一倍。這點我反而覺得真實:因為 XStore 在寫數(shù)據(jù)頁的同時,還要寫一份 Undo。物理寫入翻倍,吞吐下降是必然的。如果一個系統(tǒng)告訴你 "原位更新 + Undo 還更快",那我反而會不太信。
四、創(chuàng)新實驗:模擬 1 千萬數(shù)據(jù)的存儲膨脹對比
我設(shè)計了一項創(chuàng)新實驗:在 1000 萬條級別的大數(shù)據(jù)量下,評估 XStore 與 Heap 表在高頻更新下的空間膨脹、索引穩(wěn)定性以及查詢性能表現(xiàn)。該實驗主要有兩個創(chuàng)新點:
大規(guī)模數(shù)據(jù)模擬
使用
generate_series(1,10000000)生成 1000 萬條數(shù)據(jù),保證數(shù)據(jù)量級對存儲膨脹影響明顯。初始數(shù)據(jù)包括
id、name、value和updated_at四列,與前期實驗一致,但數(shù)據(jù)量增加十倍,以模擬真實大規(guī)模 OLTP 系統(tǒng)負(fù)載。
多維度空間分析
不僅監(jiān)控表總大小,還分別統(tǒng)計索引占用和 TOAST 表空間。
每輪更新后,通過
pg_relation_size、pg_total_relation_size和pg_indexes_size獲取精細(xì)化指標(biāo)。引入 可視化趨勢分析,繪制表空間增長曲線,以直觀展示 XStore 與 Heap 的差異。
![]()
4.1 實驗設(shè)計
表結(jié)構(gòu)
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 萬條數(shù)據(jù)
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; ![]()
先對現(xiàn)在存入 1000w 數(shù)據(jù)的空間監(jiān)控與記錄一下如下。
![]()
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多輪全表更新
連續(xù) 5 輪更新,每輪更新
value和updated_at,模擬寫入密集場景:
UPDATE xstore_large SETvalue = value + 1, updated_at = CURRENT_TIMESTAMP; UPDATE heap_large SETvalue = value + 1, updated_at = CURRENT_TIMESTAMP; ![]()
空間監(jiān)控與記錄
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 千萬數(shù)據(jù)更新膨脹可視化
![]()
![]()
五、實驗結(jié)論
這組 1000 萬級數(shù)據(jù) + 多輪全表更新的實驗,其實把 PG 傳統(tǒng) Heap 表的 "老問題" 放大得非常清楚。
最核心的對比結(jié)果只有一句話:
XStore 的空間是線性的、可預(yù)測的;Heap 表的空間是失控的、不可預(yù)測的。
具體來看:
表空間膨脹
a. Heap 表在第一次更新后,表體空間直接翻倍,從 789MB 飆到 1578MB。
b. 之后每一輪更新,雖然增長幅度趨緩,但空間再也回不到初始狀態(tài)。
c. XStore 從頭到尾不變: 985MB → 985MB → 985MB
索引體積穩(wěn)定性
a. Heap 表索引從 214MB 膨脹到 428MB,且在后續(xù)更新中保持 "高位橫盤"。
b. XStore 的索引尺寸始終維持在 388MB 左右,沒有明顯漂移。
更新行為本質(zhì)差異
a. Heap:每一次 UPDATE,本質(zhì)都是 DELETE + INSERT → 老版本殘留 → 表膨脹 → 索引碎片 → autovacuum 壓力。
b. XStore:真正的原位更新 → 歷史版本進(jìn) Undo → 主表物理頁不變 → 無膨脹。
長期可運維性
a. 在 Heap 表上,如果你不 VACUUM,它一定會慢; 如果你 VACUUM,系統(tǒng)一定會抖。
b. 在 XStore 上,這兩件事都不再是必選項。
這意味著什么?
它不是讓你飛起來,而是讓你不再塌方。
六、我的心得
說實話,這幾年我已經(jīng)對 "新一代數(shù)據(jù)庫內(nèi)核" 這類說法有點免疫了。大多數(shù)項目,要么是在 PG 上糊一層分布式殼; 要么就是換個名字,重新賣一遍 MVCC。而 XStore 給我的感覺不一樣。它沒有試圖掩蓋代價。寫入更慢, IO 更多,架構(gòu)更復(fù)雜。
但它正面承認(rèn)了一個事實:
PostgreSQL 的 MVCC,在高頻更新場景下已經(jīng)接近物理極限。
這不是參數(shù)調(diào)優(yōu)能解決的事,也不是加機器能扛住的事,而是存儲模型本身的問題。這些年我見過太多系統(tǒng):白天 QPS 很穩(wěn),半夜 autovacuum 開始清垃圾,延遲突然拉長,業(yè)務(wù)報警,DBA 開始手工 VACUUM / REINDEX / CLUSTER,第二天繼續(xù)循環(huán)。
這不是運維水平的問題,而是模型在和現(xiàn)實硬扛。XStore 讓我第一次意識到:原來 PG 也可以選擇不走這條老路。它沒有追求 "更快",而是選擇了一個更難、但更穩(wěn)的方向:
用 Undo 換空間可控
用寫放大換性能平滑
用工程復(fù)雜度換系統(tǒng)長期可預(yù)期性
如果你是寫多、更新密集型 OLTP 系統(tǒng),如果你被表膨脹、索引碎片、autovacuum 抽風(fēng)折磨過,那你會和我一樣 --- 不一定立刻用它,但你會開始認(rèn)真看它。這大概就是我這次拆源碼、跑實驗,最大的收獲。
作者:難忘兄
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
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.