在 PostgreSQL 裡,很多工程師都會遇到一個問題:到底該用哪種資料結構來存資料?要用 array(ARRAY)來存比較單純的資料?還是用 text(TEXT)欄位來存字串?又或者,HSTORE 來存「鍵-值」對?當然,還有一個問題:什麼時候該用 JSON 或 JSONB 呢?
為了幫你搞懂這些,我們會聊聊每種方式的優缺點,還有給你一些實際用法的例子。
什麼時候該用 array(ARRAY),什麼時候該用 JSONB?
Array(ARRAY)超適合存一堆同樣型別的資料。像是你有一個學生的分數清單,或是一個紀錄的標籤,array 就很剛好。
Array 範例:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT,
grades INTEGER[] -- 分數 array
);
INSERT INTO students (name, grades)
VALUES ('Alice', ARRAY[90, 85, 88]),
('Bob', ARRAY[70, 75, 78]);
另外一方面,JSONB 比較適合存比較複雜、巢狀的資料結構。如果你想要每個紀錄都多存一些額外資訊,像是每個分數的說明,就可以用 JSONB。
JSONB 範例:
CREATE TABLE students_json (
id SERIAL PRIMARY KEY,
name TEXT,
grades JSONB -- 分數資料的物件
);
INSERT INTO students_json (name, grades)
VALUES ('Alice', '{"數學": 90, "自然": 85, "英文": 88}'),
('Bob', '{"數學": 70, "自然": 75, "英文": 78}');
主要差異
| 比較項目 | Array(ARRAY) |
JSONB |
|---|---|---|
| 結構 | 同一型別的資料 | 複雜巢狀資料結構 |
| 資料存取 | 用 index:grades[1] |
用 key:grades->'數學' |
| 索引支援 | 只能對整個 array 用 GIN 或 BTREE |
可以針對 key 用 GIN 和 BTREE 索引 |
| 什麼時候用 | 簡單的資料清單(標籤、分數、ID) | 有 key 跟 value 的複雜物件 |
Array 跟 JSONB 互轉範例
來看看怎麼把資料從 array 轉成 JSONB,或反過來:
Array → JSONB
SELECT to_jsonb(grades) AS grades_jsonb
FROM students;
-- 結果:
-- [{"90","85","88"}]
JSONB → Array
SELECT array_agg(value::INTEGER) AS grades_array
FROM jsonb_array_elements_text('["90", "85", "88"]');
-- 結果:
-- {90,85,88}
JSONB 跟 text(TEXT)資料比較
Text 欄位很適合你只想存字串或一點點沒結構的資料。如果你只要做字串比對搜尋,像是產品名稱或描述,TEXT 就很夠用了。
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT,
description TEXT
);
INSERT INTO books (title, description)
VALUES ('SQL 基礎', 'SQL 的簡明入門'),
('進階 PostgreSQL', 'PostgreSQL 效能深入指南');
什麼時候該用 JSONB?
如果你的字串內容變成有巢狀結構(像是描述裡還有分類、標籤清單),那就該用 JSONB 了。
CREATE TABLE books_json (
id SERIAL PRIMARY KEY,
info JSONB
);
INSERT INTO books_json (info)
VALUES ('{"title": "SQL 基礎", "tags": ["初學者", "資料庫"]}'),
('{"title": "進階 PostgreSQL", "tags": ["效能", "最佳化"]}');
主要差異
| 比較項目 | Text(TEXT) |
JSONB |
|---|---|---|
| 結構 | 沒結構的資料 | 有結構、巢狀資料 |
| 搜尋 | 全文字搜尋 | 可以用 key、value、巢狀結構搜尋 |
| 資料修改 | 只能整個換掉 | 可以只改某個 key |
| 什麼時候用 | 單純的字串 | 複雜的 key-value 資料 |
JSONB 跟 HSTORE 比較
HSTORE 算是 JSONB 的前輩,可以存「鍵-值」對。像是你的資料結構很簡單(不需要巢狀或 array),HSTORE 會比較輕巧又快。
CREATE TABLE products (
id SERIAL PRIMARY KEY,
attributes HSTORE
);
INSERT INTO products (attributes)
VALUES ('"顏色"=>"紅", "尺寸"=>"M"'),
('"顏色"=>"藍", "尺寸"=>"L"');
為什麼 JSONB 取代了 HSTORE?
雖然 HSTORE 很方便存「鍵-值」對,但它不支援巢狀跟 array,所以 JSONB 更萬用。如果你的資料已經不只是單純物件,JSONB 就是下一步啦。
主要差異
| 比較項目 | HSTORE | JSONB |
|---|---|---|
| 結構 | 「鍵-值」對,沒巢狀 | 完整巢狀結構 |
| Array 支援 | 沒有 | 有 |
| 搜尋 | 只能用 key 搜尋 | 可以用 key、value、巢狀結構搜尋 |
| 什麼時候用 | 簡單的鍵-值 | 複雜資料結構 |
怎麼選資料型別?
如果你:
- 結構很簡單 — 清單或同型資料,就用 array(
ARRAY)。 - 單純字串或描述,就用 text 欄位(
TEXT)。 - 沒巢狀的「鍵-值」對,就選
HSTORE。 - 有巢狀物件、array、複雜資料結構 — 你要 JSONB。
格式互轉範例
TEXT → JSONB
SELECT to_jsonb('簡單文字範例') AS jsonb_form;
-- 結果: "簡單文字範例"
JSONB → TEXT
SELECT info::TEXT AS text_form
FROM books_json;
-- 結果: {"title": "SQL 基礎", "tags": ["初學者", "資料庫"]}
HSTORE → JSONB
SELECT hstore_to_jsonb(attributes) AS jsonb_form
FROM products;
-- 結果: {"顏色": "紅", "尺寸": "M"}
JSONB → HSTORE
SELECT jsonb_to_hstore('{"顏色": "紅", "尺寸": "M"}') AS hstore_form;
-- 結果: "顏色"=>"紅", "尺寸"=>"M"
要注意什麼?
如果你想要彈性最大、支援複雜結構,就選 JSONB。不過,如果你的需求只是簡單資料結構,像是 array、text 或「鍵-值」對,就用對應的資料型別(ARRAY、TEXT、HSTORE)。
記得,選對資料結構可以讓你之後開發省很多麻煩,查詢效能也會更好!
GO TO FULL VERSION