JSON 跟 JSONB 最大的差別之一就是資料儲存的格式。JSON 是把資料存成純文字,JSONB 則是存成二進位格式。意思就是:
- JSON 會把你傳進來的資料原封不動存起來。比如你插入
{"title": "PostgreSQL", "tags": ["database", "SQL"]}這個字串,它就會照原樣存下去。 - JSONB 則是先 parse 一下 JSON 物件,把多餘的空白去掉、把 key 排好順序、優化結構,然後才存成二進位格式。
這樣的優化讓 JSONB 在處理資料時,尤其是複雜的查詢、篩選、搜尋、排序時會快很多。
讀寫效能比較
JSON 跟 JSONB 在讀寫速度上有不同的特性:
- JSON 寫入資料庫會比較快,因為不用先 parse 資料就能直接存。但讀取跟處理這些資料時會比較慢,因為 PostgreSQL 查詢時還要再 parse 一次。
- JSONB 寫入時會慢一點,因為存之前要先處理資料。不過讀取、篩選、抓值都會快很多,所以如果你要做分析或搜尋,JSONB 會比較適合。
舉個例子:
-- 建立 JSON 跟 JSONB 的資料表
CREATE TABLE json_example (data JSON);
CREATE TABLE jsonb_example (data JSONB);
-- 插入資料
INSERT INTO json_example VALUES ('{"key": "值", "tags": ["json", "例子"]}');
INSERT INTO jsonb_example VALUES ('{"key": "值", "tags": ["jsonb", "例子"]}');
-- 篩選資料
SELECT * FROM json_example WHERE data->'key' = '"值"'; -- 比較慢
SELECT * FROM jsonb_example WHERE data->'key' = '"值"'; -- 比較快
資料索引
JSONB 最大的優點之一就是支援索引。PostgreSQL 可以幫 JSONB 欄位建立索引,用 GIN 這種索引型態。這樣搜尋跟篩選資料會快超多。
建立索引的範例:
-- 在 JSONB 欄位上建立索引
CREATE INDEX idx_jsonb_tags ON jsonb_example USING gin (data->'tags');
反過來說,JSON 是不支援索引的,所以如果你要做複雜的搜尋或篩選,JSON 就沒那麼適合。
什麼時候用 JSON,什麼時候用 JSONB
JSON 比較適合這幾種情境:
- 你想要把資料原封不動存下來,不想被改動。
- 你不打算常常對 JSON 資料做篩選、搜尋或排序。
- JSON 資料主要是要傳給其他系統或前端,格式不能變(比如 API 回傳給前端)。
範例:
-- 純粹儲存 JSON,不做分析
CREATE TABLE api_responses (
id SERIAL PRIMARY KEY,
response JSON
);
-- 插入 API 回傳的資料
INSERT INTO api_responses (response)
VALUES ('{"status": "成功", "payload": {"id": 123, "name": "John"}}');
JSONB 適合這些情境:
- 你會常常根據 JSON 裡面的值做篩選、搜尋、分組或排序。
- 你比較在意讀取效能,不太在意寫入速度。
- 你想要用索引來加速 JSON 資料的操作。
範例:
-- 用 JSONB 儲存資料,方便分析跟操作巢狀物件
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSONB
);
-- 插入資料
INSERT INTO products (details)
VALUES ('{"name": "筆電", "price": 1200, "tags": ["電子產品", "電腦"]}');
-- 搜尋有 "電子產品" 標籤的商品
SELECT * FROM products
WHERE details @> '{"tags": ["電子產品"]}';
關於 @> 跟 --> 這些 operator 的用法,之後的講座還會再講 :P
JSON 跟 JSONB 的操作範例
我們來建立兩個資料表:一個用 JSON 欄位,一個用 JSONB:
CREATE TABLE json_table (
id SERIAL PRIMARY KEY,
data JSON
);
CREATE TABLE jsonb_table (
id SERIAL PRIMARY KEY,
data JSONB
);
插入資料的方式兩個表都一樣:
INSERT INTO json_table (data)
VALUES ('{"key": "值", "tags": ["json", "例子"]}');
INSERT INTO jsonb_table (data)
VALUES ('{"key": "值", "tags": ["jsonb", "例子"]}');
現在我們來查找 key 是 值 的資料:
-- 查 JSON
SELECT * FROM json_table
WHERE data->>'key' = '值';
-- 查 JSONB
SELECT * FROM jsonb_table
WHERE data->>'key' = '值';
如果資料量不大,效能差異其實感覺不太出來。但如果你有幾百萬筆資料,JSONB 的效能會好很多,尤其是你有建立索引的話:
CREATE INDEX idx_jsonb_key ON jsonb_table USING gin ((data->>'key'));
處理巢狀物件跟陣列,JSONB 也比較有效率:
-- 從陣列抓第一個 tag
SELECT data->'tags'->>0 AS first_tag
FROM jsonb_table;
優缺點總結
| 特性 | JSON | JSONB |
|---|---|---|
| 資料儲存 | 原封不動存成純文字 | 存成二進位格式,key 會排序 |
| 寫入效能 | 比較快,因為直接存原始資料 | 比較慢,因為要先 parse |
| 讀取效能 | 比較慢,查詢時要 parse | 比較快,已經優化好可以直接讀 |
| 索引 | 不支援 | 支援(GIN、BTREE 索引) |
| 篩選 | 慢 | 快 |
| 操作支援 | 有限 | 功能多 |
到底要選 JSON 還是 JSONB,其實看你的需求。如果你只是想把資料原封不動存下來,選 JSON 就對了。如果你會常常對資料做篩選、搜尋、分組,JSONB 會更快更方便。
如果你的應用很複雜,JSON 資料不只是「存著而已」,還會拿來做分析,JSONB 絕對是你的好幫手。所以如果你猶豫的話,直接選 JSONB 吧!說不定你未來的「人生最快查詢」會感謝你現在的選擇!
GO TO FULL VERSION