跳到主要內容
Lab Grimoire
TW
請喝咖啡
動手實作

資料儲存與管理:ACID、NoSQL、資料湖與分片

關聯式資料庫與 ACID、四類 NoSQL 與向量資料庫、資料倉儲與資料湖與湖倉、分片與複製、CAP 定理、RDF 三元組與欄式格式。

作者
CY
發表
AI 的資料基礎:從統計到生成式 AI · 第 6/19 篇

本系列第 6 篇|這篇回答:資料要放在哪裡?不同儲存方式各自保證什麼? 讀完這篇,你應該能:

  • 依資料型態、查詢方式,以及這次操作能不能做一半,選出對應的儲存
  • 說明 ACID、CAP 與分片各在保證什麼,並依資料需求或故障徵兆判斷何時使用
  • 分辨資料倉儲、資料湖與湖倉,判斷要先定結構、先收原始資料,還是在湖上補上交易與版本

一、儲存方案是取捨,不是排名

儲存比的是它答應哪一種保證,不是排行榜上的名次。

詳細說明

結帳、商品目錄、行為日誌、月報,要的保證並不相同。有的寫入不能少做一步,有的結構下個月就會改,有的查詢是把大量列加總。儲存比的是它答應哪一種保證,不是排行榜上的名次。讀題時先圈出需求,再對儲存;順序反過來,就容易把產品名稱當成答案。

關聯式資料庫(RDBMS)把資料放在表格裡。欄位與表之間的關係在寫入前就定好,這種做法叫 schema-on-write。查詢用 SQL。它支援交易,適合「這幾步必須一起成立」的操作。

這類操作要的四項合稱 ACID。原子性(Atomicity)是交易內的動作全部成功,否則全部不做:轉帳不能只扣了款、對方卻沒入帳。一致性(Consistency)是交易前與交易後都符合已定的約束,例如庫存不能扣成負數、轉出金額與轉入金額要對得起來。隔離性(Isolation)是並行的交易互不干擾;A 還沒提交的半成品,B 不該當成已經成立的數字來用。持久性(Durability)是一旦提交,即使當機,這筆結果也不會消失。扣庫存、轉帳不能做一半,要的就是這四項。

讀寫形態再把系統分成兩類。OLTP(線上交易處理)面對大量小筆、要立刻完成的寫入,例如一筆訂單、一次扣庫存。OLAP(線上分析處理)面對大量讀取與彙總,例如把各地區金額加總成報表。同一批訂單可以既是交易的對象,也是分析的原料;負責立刻寫對的系統,和負責掃歷史再彙總的系統,承擔的工作不同。

機器不夠用時有兩條路。垂直擴展是換成一台更強的機器,上限就是那一台的處理器、記憶體與磁碟。水平擴展是加上更多機器一起分擔。資料若仍全部擠在單一節點,多出來的機器接不到這些資料,容量不會因此變大。後面的分片,就是把「加機器」落到「資料怎麼切開」。

多台機器之間還會遇到聯絡中斷。CAP 定理說:分散式系統發生網路分區(P)時,只能在一致性(C)與可用性(Availability)(A)之間取捨。這裡的 C 是各節點看到同一份最新資料,與 ACID 那個管約束規則的 C 不是同一件事。偏向 C,分區期間可能拒絕部分請求,以免兩邊各改各的;偏向 A,分區期間仍然回答,但讀到的可能還不是最新。BASE(基本可用、軟狀態、最終一致)站在可用性這一側:服務先保持能用,狀態允許暫時分歧,之後再收斂。

二、各類儲存與適用情境

離開「固定表格,加上不能做一半的交易」之後,改看三件事:一筆資料長什麼樣子、查詢沿著什麼找、錯了的後果是讀到舊資料,還是帳本身不成立。

鍵值、文件、寬欄與圖形

鍵值、文件、寬欄與圖形各自擅長不同的查詢。

詳細說明

NoSQL 常分成四類,擅長的查詢不同。

鍵值(Key-Value)用一個鍵取出對應的值,例如 Redis。延遲極低,適合快取與 Session,例如這次登入的狀態、暫時放著的熱門結果。它不處理巢狀結構怎麼演變,也不沿著多人關係往下追。

文件(Document)存放半結構化資料,例如 MongoDB 常見的 JSON。一筆商品裡可以再包尺寸、顏色、各倉庫存量,下一批商品多一個欄位,也不必先改全表。內容是巢狀的、結構會變,就對上文件資料庫。

寬欄(Wide-column,也稱欄族)例如 Cassandra、HBase,適合大量寫入與時間序列。紀錄一筆接一筆湧入,查詢多半沿鍵與時間取出一段,而不是做多方同時更新的交易。

圖形(Graph)把資料存成節點與關係,例如 Neo4j。帳戶是節點,轉帳是邊,查詢沿著邊走。詐欺集團裡彼此轉帳形成的關聯、社群網路裡誰連著誰、推薦要走的路徑,問的都是關係,不是某一欄的合計。

向量與知識表示

向量資料庫用相似度找相近內容,知識圖譜用 RDF 三元組記事實。

詳細說明

向量資料庫存的是嵌入向量(embedding)。語意接近的文字或商品,向量在空間裡也接近。查找時用近似最近鄰(ANN)索引加快相似度搜尋,例如 HNSW,而不是把高維向量逐筆精確比完整張表。語意搜尋、推薦與 RAG 都在找相近內容,所以走相似度,不走精確鍵值,也不是 SQL 的加總。

知識圖譜是知識的表示,不是上一小節那個儲存引擎的別名。它用 RDF 三元組寫下一則事實:主詞、述詞、受詞。例如「(台北, 位於, 台灣)」:台北是主詞,位於是述詞,台灣是受詞。查詢語言是 SPARQL。若資料把知識寫成三段,且中間一段是關係或動作,對應的是 RDF。

倉儲、資料湖與湖倉

資料倉儲在寫入時定結構,資料湖在讀取時才定,湖倉在湖上加管理。

詳細說明

分析用的大量歷史,還要分「進庫前整不整理」。

資料倉儲(Data Warehouse)收整理過的結構化資料,同樣是 schema-on-write,服務 BI 報表。欄位意義先講好,彙總才問得穩。

資料湖(Data Lake)是原始資料先存下來。log、影像、表格檔都可以,成本低、格式彈性大。結構等到讀取時才定義,稱為 schema-on-read。適合現在還不知道以後怎麼分析,但原始資料不能丟。若沒有人管這些資料是什麼、誰能看、從哪裡來,湖會變成資料沼澤:檔案都在,卻無法放心拿來算。

湖倉(Lakehouse)底下仍是資料湖的彈性,上面加上交易與結構管理。例如 Delta Lake、Apache Iceberg 提供 ACID 與版本,讓湖上的資料也能可靠地更新,而不是只能一直追加無法管理的檔案。

分片、複製與分區

分片看容量與吞吐,複製看可用性與讀取,分區看這次掃多少。

詳細說明

分片(Sharding)依分片鍵把資料水平切到多個節點。目的是突破單機的儲存容量與讀寫吞吐上限。分片鍵若讓幾乎所有新資料都落在同一節點,該節點就成為熱點,擴展等於沒有發生。切開之後,一個查詢要的資料可能散在多個節點,必須跨節點才彙總得起來。「切出去以後每個查詢都只打一台」不是它的保證。

複製(Replication)是同一份資料存多份。多一處可以讀,某一份故障時也較能繼續服務,提高的是可用性與讀取能力。它不提高能存放的不同資料總量:三份副本仍是那一份內容。單機已經滿了,只做複製不會騰出空間裝新訂單。

分區(Partitioning)是在邏輯範圍上切開,例如按日期分區。查某一段日期就只掃那個分區,不必把其他日期一起讀過。它回答「這次要掃多少」;分片回答「放不放得下、寫不寫得動」。

欄式格式與治理

欄式格式只讀用到的欄,治理補上出處與權限才能核對。

詳細說明

CSV 是列式純文字,一行一筆,適合交換,分析效率低。就算只要少數欄,讀取時仍容易整行碰到。Parquet 與 ORC 按欄存放,壓縮率高,分析時只讀用到的欄。

程式上可以對照兩種把欄位點明的寫法。各地區金額合計是:

SELECT region, SUM(amount) FROM orders GROUP BY region;

銷售資料若已寫成 Parquet,分析端只打開這次要的欄:

import pandas as pd

pd.read_parquet('sales.parquet', columns=['region', 'amount'])

columns 裡只有地區與金額,對上欄式格式「只讀需要的欄位」。

資料要能長期拿來算,還要資料治理。中繼資料(metadata)描述資料本身,資料目錄(catalog)讓人找得到有哪些資料,資料血緣(lineage)記錄資料從哪來、經過哪些處理,存取權限規定誰能讀、誰能改。這些不是另一種資料庫,而是湖、倉儲與湖倉都需要的管理。少了出處與權限,格式再有彈性,數字也無從核對。

三、容易混淆的地方

下表每一列都是實務上容易混淆的一對詞。先確認系統需要哪一種保證,再對產品名稱。

容易混淆 差別在哪 實際遇到時的線索
資料湖 vs 資料倉儲 湖先收任何原始格式,讀時才定結構(schema-on-read);倉儲收整理過的結構化資料,寫入時就定結構(schema-on-write),服務 BI 報表 資料流程要先保存原始格式、之後再決定分析方式時用湖;結構已定並要產出固定報表時用倉儲
分片 vs 複製 分片把不同筆資料切到不同節點,提高容量與吞吐上限;複製把同一份存多份,提高可用性與讀取,不提高不同資料的總量上限 監控顯示單機容量或 I/O 到頂時用分片;系統需要降低當機影響並讓多處可讀時用複製
分片 vs 分區 分片為跨節點擴展容量與吞吐;分區為少掃,例如按日期只讀該段 查詢紀錄顯示磁碟或吞吐不夠時用分片;若只查一段日期、避免全表掃描,則用分區
文件資料庫 vs 關聯式資料庫 文件庫放 JSON 這類巢狀、結構可變的半結構化資料;關聯式是預先定義 schema 的表格,並支援交易 資料呈現巢狀規格且欄位會增減時用文件資料庫;扣款或轉帳不能做一半時用關聯式資料庫
圖形資料庫 vs 知識圖譜 圖形資料庫是儲存系統,存節點與關係;知識圖譜是知識表示,用 RDF 三元組,可用 SPARQL 查 產品需求要沿關係找詐欺環或推薦路徑時用圖形資料庫;知識以主詞、述詞、受詞表示並用 SPARQL 查詢時,對應 RDF/知識圖譜
ACID 的 C vs CAP 的 C ACID 的一致性是交易前後仍符合約束規則;CAP 的一致性是各節點看到同一份最新資料 系統事件紀錄談餘額或庫存約束時對應 ACID;談網路分區時各節點是否看到同一份最新資料,則對應 CAP

四、基礎練習

第 1 題

某電商同時有三項需求:商品規格是巢狀的,而且欄位會增減;要對 1,536 維的商品向量做相似搜尋;結帳扣庫存不能做一半,而且這類小筆寫入要立刻完成。儲存應怎麼配?

  • (A) 三項需求全部放進資料湖,等讀取時再定義結構。
  • (B) 三項需求全部改用 Redis 這類鍵值儲存。
  • (C) 巢狀規格用文件資料庫,向量相似搜尋用向量資料庫,扣庫存用支援 ACID 的關聯式資料庫。
  • (D) 向量放進關聯式資料庫,扣庫存放進文件資料庫,而且不處理交易是否完整。
看答案與解析

答案:C

三項需求要的保證不同。巢狀、結構會變的商品規格對上文件資料庫。1,536 維向量的相似搜尋對上向量資料庫的 ANN。扣庫存不能做一半,又是 OLTP 那種立刻完成的小筆寫入,對上支援 ACID 的關聯式資料庫。

  • (A) 資料湖用 schema-on-read 先收原始資料,不負責低延遲的 ACID 扣庫存,也不會因此變成文件庫或 ANN 索引。
  • (B) Redis 適合快取與 Session,延遲極低,但不是巢狀文件、高維相似度與約束交易的共同答案。
  • (D) 需要 ACID 的扣庫存被放到不處理交易的文件資料庫,保證放錯;向量相似搜尋也不是關聯式表格的工作。

第 2 題

某電商的訂單都在單一資料庫節點上,儲存空間與 I/O 已經到上限。團隊決定分片。這項決定主要在做什麼?

  • (A) 多留一份備份,以免這台機器故障。
  • (B) 把資料加密,避免被讀走。
  • (C) 讓以後每一個查詢都只接觸一個節點,不必跨節點。
  • (D) 依分片鍵把資料水平切到多個節點,突破單機的儲存容量與讀寫吞吐上限。
看答案與解析

答案:D

單機的儲存與 I/O 到頂,缺的是容量與吞吐。分片把不同資料依分片鍵水平分散到多個節點,就是為了這個上限。

  • (A) 多留一份以免故障,是複製;複製不提高能存放的不同資料總量。
  • (B) 分片不負責加密。
  • (C) 分片後,一筆查詢要的資料可能落在不同節點,反而可能跨節點;「讓查詢不必跨節點」不是分片目的。

第 3 題

某支付服務要找出彼此轉帳、形成環狀的可疑帳戶群。資料已經有帳戶與每筆轉帳。哪一種做法對上這個問題?

  • (A) 用鍵值資料庫,以帳戶編號當鍵存餘額。
  • (B) 用圖形資料庫,把帳戶當節點、轉帳當關係,沿著關係找環。
  • (C) 把流水存成欄式檔案,重點放在壓縮。
  • (D) 在資料倉儲做一張依月份彙總的金額表。
看答案與解析

答案:B

可疑之處在帳戶之間的轉帳關係形成環,查詢要沿著關係走。圖形資料庫把帳戶存成節點、轉帳存成關係,就是這種儲存。

  • (A) 鍵值資料庫用鍵取單筆,例如用帳戶編號取餘額,不沿著多層轉帳找環。
  • (C) 欄式檔案解決按欄壓縮與少讀欄位,不表示節點與關係。
  • (D) 月份彙總表把金額加總,環狀的帳戶路徑在加總後不再存在。

第 4 題

某醫療知識庫把一則事實寫成「(阿斯匹靈, 治療, 頭痛)」,供之後查詢。這種表示法是什麼?

  • (A) RDF 三元組:主詞、述詞、受詞。
  • (B) 鍵值對:只含鍵與值。
  • (C) One-Hot:把類別編成向量。
  • (D) 星狀綱要(star schema):資料倉儲的組織方式。
看答案與解析

答案:A

這則事實分成三段。阿斯匹靈是主詞,治療是述詞,頭痛是受詞,正是 RDF 三元組。知識圖譜用這種三元組表示知識,並可用 SPARQL 查詢。

  • (B) 鍵值對只有鍵與值兩段,沒有述詞這個角色。
  • (C) One-Hot 把類別編成 0 與 1,不是主詞、述詞、受詞。
  • (D) 星狀綱要是資料倉儲組織結構化資料的方式,不是這則三段式知識。

第 5 題

某工廠想先留下各種原始 log、影像與表格,分析方式等以後再決定。較合適的儲存是哪一種?

  • (A) 資料倉儲:先把所有來源改成固定表格結構再入庫。
  • (B) 記憶體快取:靠極低延遲把這些資料長期放著。
  • (C) 資料湖:原始格式先存,採用 schema-on-read,讀取時才定義結構。
  • (D) 單機上的一個 CSV:全部收成同一份列式純文字。
看答案與解析

答案:C

需求是任何原始格式先留下,日後才決定怎麼分析。資料湖成本低、格式彈性大,結構在讀取時才定義,就是 schema-on-read。

  • (A) 資料倉儲是 schema-on-write,要先整理成結構化資料再服務報表,與「先收、以後再決定」相反。
  • (B) 記憶體快取對上極低延遲的暫時資料,例如 Session,不是長期保存 log、影像與表格。
  • (D) 單機 CSV 是列式純文字,有單機容量上限,也不是任何格式先存的湖。

第 6 題

某電商有一張 10 億列、200 欄的銷售表。這次分析只用其中 3 欄。哪一種讀法符合這個情況?

  • (A) 改成 CSV,因為列式純文字讀取最快。
  • (B) 用 Parquet 或 ORC 這類欄式格式,只讀需要的欄位,並利用較高的壓縮率。
  • (C) 改成 JSON,因為 JSON 最省空間。
  • (D) 先把 200 欄全部載入記憶體,再在程式裡篩出 3 欄。
看答案與解析

答案:B

這次只用 3 欄,不必讀入的欄位數是 200 − 3 = 197。Parquet、ORC 按欄存放、壓縮率高,可以只讀這 3 欄,其餘 197 欄留在檔案裡。

  • (A) CSV 適合交換,分析效率低,不是讀取最快的選擇。
  • (C) JSON 並沒有被定義成最省空間的格式;本題要的是欄式壓縮,以及只讀所需欄位。
  • (D) 先把 200 欄全部載入記憶體再篩,等於放棄欄式「只讀需要的欄」。

五、重點回顧

  • 選儲存先看資料型態、查詢方式、這次操作能不能做一半;交易、巢狀文件、向量搜尋與原始資料保存,不會由同一種儲存同時包下。
  • ACID 服務不能做一半的交易:全部成功或全部不做、前後符合約束、並行互不干擾、提交後當機仍在;扣庫存與轉帳屬於 OLTP 這一類。
  • 網路分區發生時,CAP 要你在「各節點看到同一份最新資料」與「仍然回答」之間取捨;BASE 偏向後者,並接受之後才一致。ACID 的 C 管約束規則,CAP 的 C 管各節點是否同一份最新資料。
  • 分片按分片鍵把不同資料切到多節點,提高容量與吞吐,鍵選不均會形成熱點;複製是同一份存多份,提高可用性與讀取,不提高資料總量上限;按日期分區是為了讓查詢少掃。
  • 資料倉儲是整理後的結構化資料、schema-on-write,服務 BI 報表;資料湖用 schema-on-read 先收任何原始格式,缺乏治理會變成資料沼澤;湖倉在湖上加 ACID 與版本,例如 Delta Lake、Apache Iceberg。
  • 沿著關係找環用圖形資料庫;「主詞、述詞、受詞」是 RDF 三元組,可用 SPARQL,那是知識表示。大表分析只用少數欄時用 Parquet 或 ORC;CSV 適合交換,分析效率低。

覺得有幫助? RSS · X · 請我喝杯咖啡

由上往下讀每一列,看「存什麼」如何對上右側的「適合」。

查詢方式決定儲存類型
1 / 5
鍵值列:用一個鍵取出對應的值
鍵值取回單筆、文件容納巢狀結構、寬欄支援時間序列、圖形沿關係查找,向量找相似內容。
  1. 延遲極低,適合快取與 Session,例如這次登入的狀態。它不處理巢狀結構,也不沿著關係往下追。
  2. 一筆商品可再包尺寸、顏色與各倉庫存量,下一批多一個欄位也不必先改全表。
  3. 紀錄一筆接一筆湧入,多半沿鍵與時間取一段,而不是做多方同時更新的交易。
  4. 帳戶是節點、轉帳是邊,詐欺關聯、誰連著誰與推薦路徑問的都是關係,不是某一欄的合計。
  5. 向量資料庫存的是嵌入;查詢不是取回某一筆,而是找出最相近的幾筆。

先看最左的資料湖,再順著箭頭看湖倉補了什麼、資料倉儲何時定結構。

結構定義從讀取走向寫入
1 / 3
資料湖節點出現,讀取時才定結構
資料湖讀取時定義結構,湖倉在湖上加管理,資料倉儲則在寫入時先定結構。
  1. log、影像與表格檔都能先留下。沒有人管這些資料是什麼、誰能看、從哪裡來,湖會變成資料沼澤。
  2. 底下仍是資料湖的彈性。Delta Lake 與 Apache Iceberg 提供 ACID 與版本,湖上的資料才能可靠地更新。
  3. 這裡收整理過的結構化資料,欄位意義先定好,BI 報表的彙總才可靠。

對照同一張表的兩列,看三個節點裡的範圍是切開還是重複。

分片拆資料,複製保留副本
1 / 4
分片列:A–H、I–P、Q–Z 分在三個節點
分片把不同資料放到各節點;複製讓每個節點保有相同資料。分配範圍為示意。
  1. 依分片鍵水平切開,才能突破單機的儲存容量與讀寫吞吐。新資料若幾乎都落在同一節點,該節點就成為熱點。
  2. 切開之後,查詢要的資料可能散在多個節點,必須跨節點才彙總得起來。
  3. 多一處可以讀,某一份故障也較能繼續服務。三份副本是同一份內容,能存的資料量並沒有變多。
  4. 提高的是可用性與讀取能力。單機已經滿了,只做複製不會騰出空間裝新訂單。

地區、金額、備註三欄裡,哪些格寫著讀取、哪一格寫著略過。

欄式格式只讀分析所需欄
1 / 3
列式 CSV 的地區、金額、備註都標成讀取
列式資料會沿整列讀取;Parquet 與 ORC 可只打開查詢用到的欄。
  1. CSV 是列式純文字,一行一筆,適合交換。就算只要少數欄,讀取時仍容易整行碰到。
  2. 按欄存放所以壓縮率高,分析時只打開用到的欄。這次地區與金額要算合計,備註就不跟著讀。
  3. 銷售資料若已寫成 Parquet,columns 只列地區與金額,所以只打開這次要的欄。