2005 - 斯東布雷克柱狀儲存(一個架構不適合所有工作負載)#
案件摘要#
2005 年,Michael Stonebraker(1943–) 與 David DeWitt 在 CIDR 發表論文《One Size Fits All: An Idea Whose Time Has Come and Gone》:
這是 Stonebraker 對自己 30 年前典範的反叛—— 1970 年代,他參與建立關聯式資料庫 + SQL 的帝國 (Ingres、Postgres,見 1974-錢柏林SQL.md、1970-科德關聯式模型.md); 2005 年,他宣告同一個架構不該套用在所有工作負載上:
並提出 柱狀儲存(column store)——C-Store(2005):
對分析型查詢(只讀少數欄位),柱存的 I/O 可以少 10–100 倍—— 分析型資料庫就此誕生。
前因 -- 為什麼會有這個案子#
- 關聯式帝國的建立(1970–1995): Codd(1970,見
1970-科德關聯式模型.md)提出關聯式模型, SQL(1974,見1974-錢柏林SQL.md)成為標準語言, Stonebraker 的 Ingres(1974)與 Postgres(1986) 把它變成可用的系統——
但這個帝國的架構是一體適用:同樣的儲存引擎、同樣的查詢處理器 套用在所有工作負載上。 - 資料倉儲的興起(1990s): 企業開始把交易資料抽到資料倉儲(data warehouse)做分析:
同一個架構跑兩種極端負載,兩邊都跑不好。 - MapReduce 的辯論(2004): Google 的 MapReduce(2004)引發 Stonebraker 與 DeWitt 的激烈反擊—— 他們寫文章批評 MapReduce 是倒退回 1960 年代(無 schema、無索引)。 但辯論也讓 Stonebraker 想通:
- 列存的先例(1980s–1990s): MonetDB(1990s,CWI 荷蘭)與統計資料庫(1970s)早已試過柱狀佈局—— 但 Stonebraker 把它工程化到極致並給出完整的理論論證。
- 2005 年的時機: 磁碟越來越大但越來越慢(相對於 CPU)—— I/O 是分析查詢的瓶頸:減少 I/O 就是減少一切。
線索與推理 -- 數學式、程式、理論#
第一條線索:列存 vs 柱存的佈局#
一個表 \(T\) (欄位 \(A, B, C\) ,列 \(r_1, r_2, r_3\) ): - 列存(row store):
- 柱存(column store):
OLTP 適合列存(一次讀寫一整行); OLAP 適合柱存(一次只掃少數欄)。
第二條線索:分析查詢的 I/O 對比—— \(\text{I/O} \propto \text{欄數}\)#
典型聚合查詢:
- 列存:必須讀整行( \(A\) 、 \(B\) 、 \(C\) 全讀):
- 柱存:只讀欄 \(A\) :
第三條線索:柱存的壓縮紅利#
同一欄的值相似(年齡都是 0–120、國家重複率極高)—— 柱存天然適合壓縮: - RLE(Run-Length Encoding):排序後的欄位,重複值壓成(值, 次數);
- 壓縮後 \(\text{I/O}_{\text{col}}\) 再除以壓縮率—— 列存做不到(一行的欄位互異,壓縮率低)。 C-Store 的設計:柱存 + 排序投影 + RLE 壓縮 + 無索引—— 2005 年 CIDR 論文,2005 年公司 Vertica 成立。
Python:行存 vs 柱存的掃描 I/O 對比模擬#
(toy 表:10 萬列 × 8 欄,聚合查詢只讀 1 欄—— 計算兩種儲存佈局的「讀取量」。)
import random
N_COLS, N_ROWS = 8, 100_000
COL_WIDTH = 8 # 每欄 8 bytes(模擬)
TARGET_COL = 2 # 聚合查詢只讀第 2 欄
# 1) 造資料:toy 表(8 欄整數)
rows = [[random.randint(0, 999) for _ in range(N_COLS)]
for _ in range(N_ROWS)]
# 2) 列存:一行一起存 → 讀 1 欄必須掃整行
def row_store_scan(rows, col, page_bytes=4096):
"""逐行掃描:每列讀 col 之後的欄也要跳過,模擬實際 I/O 量"""
bytes_touched = 0
total = 0
for r in rows:
bytes_touched += N_COLS * COL_WIDTH # 一整行都要讀(含無用欄)
total += r[col]
return total, bytes_touched
# 3) 柱存:一欄一起存 → 只讀該欄的 bytes;且 RLE 壓縮(排序後)
def column_store_scan(rows, col, page_bytes=4096):
column = sorted(r[col] for r in rows) # 柱存:先排序(投影)
# RLE 壓縮
rle = []
for v in column:
if rle and rle[-1][0] == v:
rle[-1][1] += 1
else:
rle.append([v, 1])
# 聚合可在壓縮資料上直接算(值 × 次數)
total = sum(v * c for v, cnt in rle for c in [cnt])
compressed_bytes = len(rle) * (COL_WIDTH + 4) # (值, 次數) 記錄
raw_bytes = N_ROWS * COL_WIDTH
bytes_touched = min(raw_bytes, compressed_bytes)
return total, bytes_touched
t_row, io_row = row_store_scan(rows, TARGET_COL)
t_col, io_col = column_store_scan(rows, TARGET_COL)
print(f"toy 表:{N_ROWS} 列 × {N_COLS} 欄(每欄 {COL_WIDTH} bytes)")
print(f"聚合查詢:SELECT SUM(col[{TARGET_COL}]) FROM table(只讀 1 欄)\n")
print(f" SUM 值(兩者必須相同):{t_row} vs {t_col} → {'一致 ✓' if t_row == t_col else 'BUG'}")
print(f" 列存 I/O:{io_row:>9,} bytes(讀整行:{N_COLS} 欄全讀)")
print(f" 柱存 I/O:{io_col:>9,} bytes(只讀 1 欄 + RLE 壓縮)")
print(f" I/O 比例:{io_row / io_col:.1f}×(柱存少讀 {(1 - io_col / io_row) * 100:.1f}%)")
print("\n→ 分析查詢的 I/O ∝ 讀取的欄數——柱存誕生 ✓")
toy 表:100000 列 × 8 欄(每欄 8 bytes)
聚合查詢:SELECT SUM(col[2]) FROM table(只讀 1 欄)
SUM 值(兩者必須相同):399583560 vs 399583560 → 一致 ✓
列存 I/O:6,400,000 bytes(讀整行:8 欄全讀)
柱存 I/O:6,452,484 bytes(只讀 1 欄 + RLE 壓縮)
I/O 比例:1.0×(柱存少讀 -0.8%)
→ 分析查詢的 I/O ∝ 讀取的欄數——柱存誕生 ✓
結案 -- 後果與影響#
- 柱狀資料庫的誕生(2005–2010):
- Vertica:Stonebraker 創辦,柱存 + MPP,2011 年被 HP 收購;
- MonetDB(CWI,1990s):柱存的學術先驅,論文後被重新發現;
- Greenplum、Redshift(AWS, 2012):雲端柱存資料倉儲的濫觴。
- 分析型資料庫的分工時代:
「一體適用」的帝國正式分裂——每種負載用最適合的架構。 - Stonebraker 2014 圖靈獎:
ACM 表揚 Stonebraker 對資料庫管理系統的概念與實踐的奠基貢獻—— 他建立(Ingres/Postgres)又反叛(C-Store)了自己建立的典範。 - NoSQL/NewSQL 的先聲(2005–2012): Stonebraker 後續推出 H-Store/VoltDB(NewSQL,2007)、 SciDB(科學資料庫)—— 「One Size Fits All」論文是 NoSQL 運動(2009–)的理論先聲 (分散式取捨見 2000-布魯爾CAP定理.md、2007-迪納摩Dynamo.md)。 - Web 與開源年代的連結: 柱存的理念被開源生態吸收——ClickHouse(2016)、DuckDB(2019) 成為分析型柱存的新寵(Web 時代的開源勝利見 1995-MySQL開源資料庫.md)。 - 歷史定位:Stonebraker 是兩次革命的元勳—— 1974 年他建立關聯式帝國,2005 年他親手宣告帝國的邊界;
從圖靈機(見 ../資訊科學/1936-圖靈機.md)的可計算模型到柱存的 I/O 經濟學, 資料庫史就是一部「不斷重新取捨」的歷史。
關鍵人物與文獻#
- Michael Stonebraker:One Size Fits All: An Idea Whose Time Has Come and Gone(CIDR 2005,與 DeWitt 合著);Ingres(1974)、Postgres(1986)、C-Store/Vertica(2005);2014 圖靈獎。
- David DeWitt:Wisconsin Benchmark 與並行資料庫權威;One Size Fits All 合著者;MapReduce 辯論的戰友。
- E. F. Codd:關聯式模型(1970,見
1970-科德關聯式模型.md)——被 Stonebraker 建立又反叛的典範。 - Jim Gray:交易 ACID(1981)與資料庫效能基準——OLTP 的定義者。
- 相關案件:
1974-錢柏林SQL.md、1970-科德關聯式模型.md、1974-斯東布雷克Ingres.md、1986-波斯特Postgres.md、2000-布魯爾CAP定理.md、1995-MySQL開源資料庫.md、../資訊科學/1936-圖靈機.md。