跳至主要內容
論文精煉 · Cloud data systems

The Snowflake Elastic Data Warehouse(Snowflake 彈性資料倉儲)

把資料倉儲拆成 blob 儲存、用完即丟的運算叢集,與共用的中繼資料大腦,讓彈性成為架構本身的性質。

作者Benoit Dageville、Thierry Cruanes、Marcin Zukowski、Vadim Antonov 等人(Snowflake Computing) 發表於SIGMOD/PODS 2016,美國舊金山 年份2014–2016
閱讀原始論文 PDF 所有論文

一口氣講完 — 整篇論文的濃縮

高效能資料倉儲當時已收斂到 shared-nothing 叢集:每個節點只負責自己本機磁碟上的資料列,於是每一次調整規模、每一次節點故障、每一次升級,都得由正在跑查詢的那批節點自己搬資料。Snowflake 保留 shared-nothing 執行引擎,卻把基礎資料搬到 Amazon S3,把系統切成三個可獨立擴展的層:S3 儲存層、被稱為 virtual warehouse 的短暫運算叢集,以及高度多租戶、掌管中繼資料、查詢最佳化、交易與安全的 Cloud Services 層。表被水平切成一批巨大且不可變的檔案,檔案內部採混合欄式(PAX)配置,查詢只需用 S3 的範圍 GET 抓下檔頭與自己要用的那幾欄;而每個檔案各自維護的 min/max 中繼資料,不需要任何索引就能整檔跳過。正因為檔案不可變,一次寫入是以「加入與移除整個檔案」的方式產生新的表版本,並記在交易式鍵值儲存中,於是 MVCC 之上的快照隔離幾乎是白撿的,連帶還撿到最長 90 天的 time travel、UNDROP,以及只複製中繼資料的 CLONE。作者描述的是一套真正上線的服務:2015 年 6 月正式對外提供,每天在數 PB 資料上跑數百萬道查詢,每週在無停機的情況下升級,而且對使用者只暴露一個調校旋鈕:你願意為多少效能付錢。

在這篇論文之前 — 它所降落的世界

整個 2000 年代,高效能資料倉儲收斂到 shared-nothing 架構:表水平切分到各節點,每個節點只負責自己本機磁碟上的資料列。這個設計會勝出,是因為星狀綱要的 join 只需要極少頻寬,而且共用結構與硬體資源幾乎沒有爭用,所以也不需要昂貴的特製硬體。但它預設的是一座規模不大、成員固定、行為乖巧的叢集:很少調整規模、很少壞節點,升級可以安排停機時段慢慢做。與此同時資料本身也變了:越來越大的比例來自應用程式日誌、網頁與行動應用、社群媒體與感測器,而且常常是無綱要的半結構化格式;傳統資料倉儲卻建立在又深又長的 ETL 管線與實體調校之上,而這些都假設資料是可預測、變動緩慢、且多半來自組織內部。社群中有一部分人轉向 Hadoop 與 Spark,但那些平台仍缺少成熟資料倉儲技術的效率與功能完整度,光是導入就要投入可觀的工程人力;因此 2012 年底 Snowflake 起步時,整個資料庫圈的目光都在 SQL on Hadoop 上,從零打造一套雲端原生的「傳統」資料倉儲,看起來是相當逆風而且冒險的選擇。

問題 — 當時真正壞掉的地方

  • 純 shared-nothing 把運算與儲存綁死,於是適合大量載入的硬體配置(高 I/O 頻寬、輕運算)並不適合複雜查詢(低 I/O 頻寬、重運算),最後只能折衷成一個平均使用率偏低的配置。
  • 任何成員變動——節點故障或使用者主動調整規模——都得搬動大量資料,而搬資料的正是同時在處理查詢的那批節點,於是彈性與可用性同時受限;而在雲端,這種變動是常態而非例外,因為節點故障頻繁,而且即使是同一種機型,效能也可能有極大差異。
  • 軟硬體升級遲早會碰到每一個節點,而當所有元件緊密耦合又被預期是同質的,要一台一台輪流升級且全程不停機就變得極為困難。
  • 越來越多倉儲資料來自外部、較難掌控的來源,格式是 JSON、Avro 這類無綱要的半結構化資料,而傳統 ETL 管線與實體調校根本沒把這件事算進去。
  • S3 是只有 PUT/GET/DELETE 介面的 blob 儲存:物件只能整份覆寫,PUT 時還必須事先宣告檔案的精確大小,而且無法在檔尾追加;因此圍繞「可變頁面」設計的檔案格式與並行控制機制完全搬不過來。
  • 傳統 B+-tree 索引在這裡是錯的存取方法:它高度仰賴隨機存取(對 S3 與壓縮檔都不利),會膨脹資料量與載入時間,而且必須由使用者明確建立,這與「沒有實體設計的純服務」完全牴觸。

核心概念 — 主要貢獻,以及它們為何成立

儲存與運算分離

Snowflake 把運算與儲存當成兩個鬆散耦合、可獨立擴展的服務:運算是自研的 shared-nothing 執行引擎跑在 EC2 上,儲存則交給 Amazon S3。這招之所以成立,是因為雲端提供了各式各樣的機型與近乎無限的儲存,要用到對的硬體只需把資料帶過去,而不必重新配置一整座固定叢集。更關鍵的是,本機磁碟不再浪費在複製那些又大又冷的基礎資料上,而是專門用來放暫存資料與快取——這兩者都是熱的,因此值得配上 SSD。等快取熱起來之後,效能可以逼近甚至超過純 shared-nothing 系統,也就是說這份彈性並沒有犧牲單節點效率換來。

Multi-cluster, shared-data 架構

整個系統是三層服務導向架構,各層之間以 RESTful 介面溝通:Data Storage 落在 S3;Virtual Warehouses 是負責執行查詢的「肌肉」;Cloud Services 則是「大腦」,管理虛擬倉儲、查詢、交易,以及綱要、存取控制、加密金鑰與使用統計等所有中繼資料。多座彼此獨立的運算叢集讀取同一份共享的表,完全不需要實體複製資料,於是同時滿足了資料倉儲與 data mart 這兩個歷來對立的目標:把所有資料整合在一處,同時給每個組織單位互不干擾的私有運算資源。Cloud Services 是高度多租戶且長時間存活的,因此使用率更高、管理成本更低,規模經濟也優於「每位使用者一套私有系統」的傳統做法。這一層的每項服務都有複本,所以單一服務節點掛掉最多只會讓少數進行中的查詢失敗,而那些查詢會被透明地重新執行。

Virtual warehouse:用完即丟的運算資源

一座 virtual warehouse 就是一群 EC2 worker node,以 X-Small 到 XX-Large 的抽象「T 恤尺寸」呈現給單一使用者,因此使用者不知道也不需要知道自己有幾個節點,而 Snowflake 也能讓服務與定價獨立於底層雲端平台演進。VW 是純運算資源:隨時可依需求建立、銷毀或改變大小,對資料庫的狀態完全沒有影響,而且論文明白鼓勵使用者在沒有查詢時把所有 VW 全部關掉。由於計價單位是 compute-hour,用 32 個節點跑 2 小時與用 4 個節點跑 15 小時的花費大致相同,但使用體驗天差地遠。這正是儲存/運算分離最深的後果:運算變成一種按工作負載拋棄式取用的資源,而不再是「擁有你資料的那個東西」。

不可變的混合欄式表檔案

表被水平切分成一批巨大且不可變的檔案,扮演傳統資料庫中 block 或 page 的角色。在每個檔案內部,同一欄的值被聚在一起並重度壓縮,也就是文獻中所稱的 PAX 或混合欄式配置;檔頭則記下每一欄在檔案中的位移。因為 S3 支援對檔案局部範圍的 GET,查詢只需抓下檔頭再抓自己真正引用的那幾欄,等於在一個根本沒有「欄」概念的物件儲存之上,重新取回欄式 I/O 的行為。不可變性不只是儲存上的方便:它讓 worker process 不產生任何外部可見的副作用,讓執行引擎完全不必管交易,也把並行控制變成一個純粹的中繼資料問題。

以 pruning 取代索引

Snowflake 不用 B+-tree,而是為每一個表檔案維護 min/max 分布中繼資料——文獻中稱為 small materialized aggregates、zone map 或 data skipping——並在最佳化階段用它排除不可能滿足述詞的檔案。若欄位 x 在檔案 f1 的範圍是 3..5、在 f2 是 4..6,那麼述詞 x >= 6 就只需要碰 f2。這份中繼資料比真實資料小上好幾個數量級,載入時維護的成本幾乎為零,天生適合對大塊資料的循序存取,最重要的是完全不需要使用者輸入任何東西——這正是一套沒有調校旋鈕的系統所需要的。同一套想法還延伸到 WEEKDAY(orderdate) IN (6, 7) 這種複雜運算式,以及半結構化文件中自動偵測出來的欄位。

建立在版本化檔案集合上的快照隔離

Snowflake 以 MVCC 之上的 Snapshot Isolation 實作 ACID 交易;論文主張這是最自然的選擇,理由正是表檔案不可變,而不可變又是採用 S3 的直接後果。一次寫入(insert、update、delete、merge)是靠加入與移除整個檔案來產生新的表版本,這些檔案的增刪都記在全域交易式鍵值儲存中,而且記錄形式讓「某個特定表版本由哪些檔案組成」可以被極有效率地算出來。既然舊版本不過是被保留下來的檔案加上一份中繼資料,同一套機制幾乎沒有額外成本地長出三個使用者看得見的功能:以 AT 與 BEFORE 表達的 time travel、UNDROP,以及只複製中繼資料的 CLONE——複製後兩張表一開始共用同一批檔案,之後各自獨立演變。論文也提到他們考慮過用 redo-undo 日誌加 delta store 來延後改動,但基於複雜度與擴展性的理由沒有採用。

VARIANT 與「先載入、後定綱要」的半結構化資料

Snowflake 新增三種型別——VARIANT、ARRAY 與 OBJECT——共用同一套自我描述的緊湊二進位編碼,支援快速的鍵值查找、型別測試、比較與雜湊,因此 VARIANT 欄位可以像一般欄位一樣當 join key、grouping key 與排序鍵。使用者不必宣告任何綱要,就能把 JSON、Avro 或 XML 直接載入 VARIANT 欄位,把 ETL 變成 ELT,之後真要做轉換時,還能動用平行 SQL 的完整能力,包括 join、排序與彙總這些傳統 ETL 工具鏈做得很差的事。真正的效能關鍵在於:系統並沒有停在一團列式的二進位 blob,而是對每個表檔案內的文件集合做統計分析、推論型別,把經常出現的定型路徑抽出來,存成貨真價實的壓縮欄,並附上自己的 pruning 中繼資料。這才是「無綱要儲存的速度幾乎追平關聯式儲存,而且不需要使用者做任何事」的原因;否則一套又要 schema later、速度又慢的系統,跟文件資料庫也就沒什麼差別了。

運作方式 — 具體的機制

表檔案、檔頭與 S3 讀取路徑

每個表檔案寫一次就不再修改,因為 S3 要求整份覆寫物件,而且大小必須在 PUT 時事先宣告。檔頭除了其他中繼資料外,還記錄每一欄在檔案中的位移,所以掃描時先對檔頭發一次範圍 GET,再對查詢真正碰到的那幾欄各發範圍 GET。S3 的用途不只放基礎資料:當本機磁碟用罄時,查詢運算子會把暫存資料溢寫到 S3,因此再龐大的 join 或彙總都能完成,不會爆記憶體或爆磁碟;大型查詢結果也放在 S3,於是傳統資料庫那種伺服器端 cursor 就不再需要。至於其餘的一切——目錄物件、某張表由哪些 S3 檔案組成、統計資訊、鎖與交易日誌——都存在 Cloud Services 內部一個可擴展的交易式鍵值儲存中,而不是放在 S3。

Worker process、本機快取、consistent hashing 與 file stealing

查詢進來時,該 VW 中的每個 worker node(若最佳化器判定是小查詢則只取其中一部分節點)各自派生一個 worker process,它只活到這道查詢結束;而且因為表檔案不可變,它永遠不會造成外部可見的副作用,所以故障可以被侷限住,通常重試一次就解決。每個 worker node 在本機磁碟維護一份 LRU 快取,內容是它讀過的檔頭與個別欄位;這份快取的壽命跟著節點走、比個別查詢長,而且對查詢本身一無所知,它看到的只是一串檔案與欄位的請求。為了提高命中率、避免同一個檔案在多個節點重複快取,最佳化器用表檔案名稱的 consistent hashing 把輸入檔案集合指派給各個 worker;而這個 hashing 是惰性的:節點增加、故障或縮編時不會立刻搬任何資料,而是讓 LRU 慢慢把快取內容換掉,如此把成本攤平、也不需要什麼「降級模式」,可用性遠優於急切重排。資料傾斜則在掃描層以 file stealing 處理:先掃完自己那份輸入的 worker 會向同儕要更多檔案,手上還剩很多檔案的同儕就把其中一個檔案的所有權讓出來(僅限這道查詢的範圍與期間),而要檔案的那一方是直接從 S3 下載,不是跟同儕拿,因此落後節點不會再被加重負擔。

Cloud Services 的最佳化器與執行引擎

每一道查詢都要先經過 Cloud Services,在此完成剖析、物件解析、存取控制與計畫最佳化;最佳化器採 Cascades 風格、由上而下的成本式搜尋,而所有統計資訊都在載入與更新時自動維護。由於沒有索引,計畫搜尋空間本來就比較小,論文還刻意再縮小它:把某些決定(例如 join 要用哪種資料分布方式)延後到執行期才決定,用一點點尖峰效能換取更少的壞計畫與更可預測的行為。計畫產生後會派送到參與這道查詢的所有 worker node,Cloud Services 接著持續追蹤查詢狀態以蒐集效能計數器、偵測節點故障,並把所有查詢資訊留存供稽核與分析。引擎本身是欄式、向量化(一次處理數千列的欄式批次,不具體化中間結果,源自 VectorWise/MonetDB-X100)且推送式的:運算子把結果往下游推,而不是被下游以 Volcano 方式拉取,這使緊迴圈裡不再有控制流邏輯,也讓執行計畫可以是 DAG 而不只是樹。執行期完全不需要交易管理,也沒有 buffer pool,但 join、group by 與排序都能溢寫到磁碟並遞迴處理。

靜態與動態 pruning

最佳化階段會拿每個檔案的 min/max 中繼資料去比對查詢述詞,在讀取任何資料之前就先裁掉輸入檔案集合;而且它不只支援單純的基本值比較,也支援 WEEKDAY(orderdate) IN (6, 7) 這類推導出來的運算式。Pruning 中繼資料是為每一個表檔案各自維護的,涵蓋一般關聯式欄位,也涵蓋半結構化資料中被自動偵測出來的部分欄位。執行期 Snowflake 還會做動態 pruning:建 hash join 時蒐集 build 端 join key 的分布統計,再把這份資訊推到 probe 端過濾資料列,甚至整個跳過 probe 端的某些檔案;這是在 bloom join 等既有技巧之外額外加的。因為中繼資料相對於資料小得可以忽略,它對載入、最佳化與執行都幾乎不增加負擔——這正是一套沒有調校旋鈕的系統敢把它當成唯一存取路徑機制的原因。

把半結構化資料變成欄式

Snowflake 對每一個表檔案獨立地做統計分析:檢視該檔案內的文件集合,進行自動型別推論,判斷哪些定型路徑經常共同出現;接著把對應的欄位從文件中拆出來,用與原生關聯式資料相同的壓縮欄式格式另外存放,並且同樣算出供 pruning 使用的具體化彙總值。掃描時這些碎片可以重新組回單一個 VARIANT 值,但既然多數查詢只要其中幾條路徑,投影與型別轉換運算式就被下推進掃描運算子,只讀必要的欄並直接轉成目標 SQL 型別。以檔案為單位各自處理,讓儲存在綱要演進下依然有效率,卻也弄壞了 pruning:某條路徑可能存在於多數檔案中,卻只在其中一部分檔案裡頻繁到值得留中繼資料。保守做法是把所有沒有中繼資料的檔案全掃一遍,Snowflake 則改為對每個檔案內文件出現過的所有「路徑」(是路徑,不是值)建 Bloom filter,與其他檔案中繼資料一起存起來,最佳化器在 pruning 時探測它,就能安全跳過不含所需路徑的檔案。另外,optimistic conversion 負責處理日期這類以字串形式抵達的值:系統在寫入時就轉換,但除非該轉換完全可逆,否則會把轉換結果與原始字串分別存成兩欄,所以資訊不會遺失;又因為沒用到的欄根本不會被讀取,這份雙份儲存對查詢效能的影響微乎其微。

故障韌性與待命節點

S3 本身跨可用區(availability zone)複製,Snowflake 也讓自己的中繼資料儲存同樣跨 AZ 分散並建立複本,Cloud Services 其餘部分則是散在多個 AZ、由負載平衡器分流的無狀態節點。因此單一節點故障、甚至整個 AZ 失效,都不會造成全系統性的衝擊,最壞的情況是當下連在該節點上的使用者查詢失敗,而他們下一道查詢就會被導向另一個節點。Virtual warehouse 則刻意不跨 AZ 佈署,因為分散式查詢執行極度依賴網路吞吐量,而同一個 AZ 內的吞吐量高出許多;若某個 worker node 在查詢途中掛掉,該查詢會失敗但被透明地重新執行,要不就從一小池待命節點(同時也用來快速開新 VW)立刻補上,要不就暫時用較少的節點跑完。唯一被接受的缺口是整個 AZ 失效:該區所有 VW 上的查詢都會失敗,使用者必須主動到別區重新開設 VW。

線上升級與背景 rekeying

所有服務實際上都是無狀態的,硬狀態全放在交易式鍵值儲存中,並透過一層對應層存取,由該層處理中繼資料的版本管理與綱要演進,且保證與前一版向後相容;這才讓整套系統的兩個版本能夠並排運行。升級時先把新版部署在舊版旁邊,再逐步把使用者帳號切到新版(切過去之後,該使用者的新查詢都送往新版),讓仍在舊版上執行的查詢跑完,最後才把舊版全部下線。兩個版本共用同一份中繼資料儲存,不同版本的 VW 甚至能共用 worker node 與其快取,所以升級後完全不必重新暖機。所有服務每週升級一次;而且升級與降級都在一套專門的預備環境中持續演練,因此一旦發現嚴重錯誤,可以很快降版或臨時出一次計畫外的修補。同一套儲存/運算分離也讓安全維運變得無感:file key 不是存起來的,而是由 table key 與唯一檔名以密碼學方式推導出來,於是 rekeying 在與查詢分開的 worker node 上重新加密檔案,再原子性地把表的中繼資料切到新檔案,等進行中的查詢都結束後才刪掉舊檔。

論文證明了什麼 — 量測數據與證明

  • 以 TPC-H 式資料在 SF100(100 GB)與 SF1000(1 TB)上測試:資料以純 JSON 形式分別載入關聯式綱要與「無綱要」綱要(每張表只有一欄 VARIANT,不給任何提示、不做任何調校),在一座 medium 標準 warehouse 上跑完 22 道查詢、取三次熱快取結果,無綱要版本的額外負擔約為 10%,唯二例外是 SF1000 的 Q9 與 Q17,作者追查出原因是 distinct value 估算的已知錯誤導致 join 順序不佳。
  • 這不是原型系統:實作始於 2012 年底,Snowflake 於 2015 年 6 月正式對外提供,論文寫作當時已在一套數百個節點的線上系統上,每天於數 PB 資料上執行數百萬道查詢。
  • 論文對彈性的具體說明是:一份用 4 個節點要跑 15 小時的資料載入,換成 32 個節點可能只要 2 小時;由於計價單位是 compute-hour,總花費非常接近,但使用體驗完全不同。
  • 容錯的基礎是 S3 的跨可用區複製,論文引用其保證 99.99% 的資料可用性與 99.999999999% 的耐久性;Snowflake 自己的中繼資料儲存也同樣跨 AZ 分散並建立複本以相匹配。
  • 線上升級是實際的營運做法而非設計理想:所有服務每週升級一次且全程不停機,兩個版本共用同一份中繼資料儲存,不同版本的 VW 共用 worker node 與快取,因此快取無須重新填充。
  • 安全方面採 AES 256 位元加密與四層金鑰階層(root、account、table、file),根植於 AWS CloudHSM;金鑰定期輪替(例如每月一次),資料則在較長週期後重新加密(例如每年一次)以走完 NIST 800-57 的金鑰生命週期,而 root key 從不離開 HSM 裝置。

限制與取捨 — 論文自承的,以及後來被發現的

  • 論文自承:Snowflake 目前不做局部重試,因此單一 worker 故障會讓整道查詢中止並從頭重跑;作者明白指出,這對非常龐大、執行很久的查詢是個隱憂。
  • 論文自承:virtual warehouse 不跨可用區佈署,這是為了網路吞吐量而刻意做的取捨,代價是整個 AZ 失效時該區所有 VW 上的查詢全數失敗,使用者必須主動到別區重新開設——這是他們接受下來的一種局部不可用情境。
  • 論文自承:worker node 從不跨 VW 共用,以使用率換來強效能隔離;worker process 又是短暫的,每道查詢都得付啟動成本。作者把 worker node 共用與行程回收都列為未來工作。
  • 論文自承:最佳化器刻意延後決策,願意用一點尖峰效能換取穩健;而論文自己的 TPC-H 數字就暴露了一個真實缺陷——distinct value 估算的錯誤,在 SF1000 的 Q9 與 Q17 上產生了糟糕的 join 順序。
  • 後續經驗揭露:既沒有索引、也不讓使用者指定實體設計,pruning 的效果就完全取決於資料是否碰巧依述詞欄位聚集;這正是 Snowflake 日後不得不補上 automatic clustering、具體化檢視與 search optimization service 的原因。另外,論文唯一的量測是自己跑的 TPC-H 式實驗且為熱快取,儘管文中討論了 Redshift、BigQuery 與 Azure SQL DW,卻沒有任何正面對比的數據。

它後來變成什麼 — 繼承這個想法的系統

Snowflake 的儲存/運算分離成為雲端資料平台的預設架構,而論文的詞彙——virtual warehouse、multi-cluster shared data、用多少付多少——也成了整個市場的詞彙;Amazon 後來以 RA3 託管儲存與 Redshift Serverless 把這個想法補進 Redshift,Azure Synapse、Firebolt、ClickHouse Cloud,以及 StarRocks 與 Apache Doris 的存算分離模式,走的都是同一個形狀。「不可變檔案加版本化中繼資料」這道配方,後來被 Apache Iceberg、Delta Lake 與 Apache Hudi 以開放格式原樣打開:它們的 snapshot、manifest 層級的 min/max 統計,以及 zero-copy 或 shallow clone,重現的正是 Snowflake 的表檔案模型、time travel 與 CLONE;而 Snowflake 自己後來把這些表檔案改稱為 micro-partition,這也是今天多數實務工作者認識它們的名字。Databricks 則以 lakehouse 正面回應,同樣把便宜的物件儲存與彈性運算拆開,只是堅持開放格式;兩者的競爭定義了此後十年的分析市場採購。VARIANT 型別與「拆分成欄」的實作影響力也足夠大,原生的 variant 型別後續被 Apache Spark 與開放表格式採納,半結構化資料成為一等公民如今是預期而非亮點。在營運面,論文那些純 SaaS 主張——每週線上升級、沒有調校旋鈕、沒有實體設計、不必做 vacuum——把客戶的期待重新設定成「資料庫是拿來用的,不是拿來管的」;而 Snowflake 在 2020 年寫下當時史上最大軟體 IPO 紀錄,也把這個架構主張變成了財務主張。業界唯一走過頭的地方,是論文假設光靠 pruning 就足以當作存取方法:automatic clustering、更豐富的檔案層級統計與各種輔助結構,都是後來才被補上的。

論文原文 — 逐字引用

“It is perfectly legal (and encouraged) that users shut down all their VWs when they have no queries.”

§3.2.1 Elasticity and Isolation

“MVCC is a natural choice given the fact that table files are immutable, a direct consequence of using S3 for storage.”

§3.3.2 Concurrency Control

“As a result, today, Snowflake has only one tuning parameter: how much performance the user wants (and is willing to pay for).”

§6 Lessons Learned and Outlook

術語 — 依本篇論文的用法

Multi-cluster, shared-data architecture(多叢集共享資料架構)
Snowflake 為自身設計取的名字:多座彼此獨立的 shared-nothing 運算叢集,共同讀取放在 blob 儲存上的同一份資料,本機磁碟只用於快取與暫存資料。它保留了 shared-nothing 的執行效率,卻把這份效率與「誰擁有資料」解耦。
Virtual warehouse(VW,虛擬倉儲)
一群 EC2 worker node,以 X-Small 到 XX-Large 的抽象 T 恤尺寸呈現給單一使用者。它是純運算資源,可隨時建立、改變大小或銷毀而不影響資料庫狀態,且每一道查詢只在恰好一座 VW 上執行。
Table file(表檔案)
儲存的基本單位:表被水平切分成的一個個巨大且不可變的檔案,相當於傳統資料庫中的 block 或 page。寫入永遠不會修改既有檔案,而是以加入與移除整個檔案的方式產生新的表版本。
PAX/混合欄式(hybrid columnar)
表檔案內部的配置方式:同一欄的值聚在一起並重度壓縮,檔頭記錄每一欄的位移。搭配 S3 的範圍 GET,查詢就只需下載自己引用到的那幾欄。
Pruning(裁剪)
利用每個檔案的 min/max 中繼資料(文獻中也稱 small materialized aggregates、zone map 或 data skipping)判定某個檔案不可能滿足述詞,於是整檔跳過。在 Snowflake 中它取代索引,成為唯一的資料存取限縮機制,而且完全不需要使用者輸入。
File stealing(偷檔案)
處理資料傾斜的技巧:先掃完自己輸入檔案的 worker process 會向同儕索取更多檔案,手上還剩很多檔案的同儕便讓出其中一個檔案的所有權,範圍與期間都僅限當前這道查詢。索取者是直接從 S3 下載該檔案而非向同儕要,因此落後節點不會被加重負擔。
VARIANT
一種 SQL 型別,可以裝任何原生 SQL 值、變動長度的 ARRAY,或由字串映射到 VARIANT 的 OBJECT,全部共用同一套自我描述的緊湊二進位編碼。由於該編碼支援快速查找、型別測試、比較與雜湊,VARIANT 欄位能像一般欄位一樣當 join key、grouping key 與排序鍵。
Optimistic conversion(樂觀轉換)
在寫入時就把日期這類以字串編碼的值轉成真正的 SQL 型別,同時把原始字串留在另一欄,除非該轉換完全可逆才省略。它換來讀取速度與日期欄位的 pruning 中繼資料,又不會在那些「只是長得像日期或數字」的值上遺失資訊。
Time travel(時光回溯)
用 AT 或 BEFORE 搭配絕對時間、相對位移或先前某道敘述的 ID,去讀取表、綱要或整個資料庫的舊版本。它之所以可行,是因為被新版本移除的檔案會保留一段可設定的期間(目前最長 90 天),UNDROP 也建立在同一份中繼資料之上。

在時間軸上的位置 — 這篇論文在整段故事中的座標

在時間軸上查看