今天我們要更深入了解陣列,然後把它跟 JSONB 做個比較,看看各自的優缺點,還有在實際專案裡怎麼選擇跟用得最順。
陣列 vs JSONB:迷你烏龜資料 vs 彈性百寶箱
你應該已經知道,在 PostgreSQL 的陣列裡只能存同一種型別的資料:像是數字、字串或日期的陣列。舉例來說:學生的成績清單,每個元素都是數字。
-- 學生跟他們成績的資料表
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT,
grades INTEGER[] -- 成績陣列
);
JSONB 跟陣列不一樣,它是用 JSON 結構來存資料。這很像大家熟悉的 JavaScript 物件,但多了快速解析跟索引的優點。JSONB 可以存有順序的清單,也可以是有 key 跟 value 的物件。
-- 學生跟各種資料的資料表
CREATE TABLE students_details (
id SERIAL PRIMARY KEY,
name TEXT,
details JSONB -- 彈性的 JSON 結構
);
JSONB 資料範例:
{
"grades": [90, 82, 77],
"address": {
"city": "Berlin",
"zip": "352912"
}
}
所以說,陣列就是簡單處理清單的方式,而 JSONB 則能搞定更複雜的資料。
陣列跟 JSONB 的主要差異
| 特徵 | 陣列 | JSONB |
|---|---|---|
| 結構型態 | 線性資料結構 | 階層式資料結構 |
| 元素型態 | 只能一種資料型態 | 可以混合多種資料型態 |
| 結構大小 | 固定(線性) | 彈性,可以有清單跟物件 |
| 存取速度 | 資料固定時很快 | 複雜查詢時會慢一點 |
| 索引 | 支援索引效果不錯 | 需要 GIN 這種索引 |
| 應用場景 | 簡單清單或值的陣列 | 複雜資料:巢狀物件/清單 |
接下來看看實際上怎麼用。
什麼時候該用陣列?
假設我們有一本書的資料庫,每本書可以屬於多個類型。這時候用陣列就很適合。
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT,
genres TEXT[] -- 類型陣列
);
-- 插入一本有多個類型的書
INSERT INTO books (title, genres)
VALUES ('1984', ARRAY['Dystopia', 'Political Fiction', 'Science Fiction']);
如果你確定:
- 你的資料就是清單,沒有複雜結構,
- 清單不會太大而且型態都一樣(像字串或數字),
- 你只需要存跟取清單(不用搞很複雜的操作)。
陣列的優點
- 存同型資料超簡單。
- 很適合小清單,像標籤、分類或成績。
什麼時候該用 JSONB?
現在假設你想存更複雜的書本資料,包括類型、ISBN 跟評分。這時候陣列就不夠用了——該上 JSONB 了。
CREATE TABLE books_details (
id SERIAL PRIMARY KEY,
title TEXT,
details JSONB -- 書本細節用 JSONB
);
-- 插入一本書的複雜資料
INSERT INTO books_details (title, details)
VALUES (
'1984',
'{"genres": ["Dystopia", "Political Fiction", "Science Fiction"],
"isbn": "9780451524935",
"rating": 8.9}'
);
如果你需要:
- 存複雜或混合型態的資料(數字、字串、清單、物件),
- 動態加欄位,不想改資料表結構,
- 存巢狀資料(像地址、屬性、設定)。
JSONB 的優點
- 超彈性。你可以隨時加 key 跟 value,不用改表。
- 很適合存複雜資料,像 API 回傳的 JSON。
怎麼選陣列還是 JSONB?
如果只要存同型清單——就用陣列。 舉例:
-- 存活動參加者 ID
CREATE TABLE events (
id SERIAL PRIMARY KEY,
participant_ids INTEGER[]
);
如果資料很雜或很複雜——就用 JSONB。 舉例:
-- 存有地址的客戶資料
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
info JSONB
);
陣列跟 JSONB 的索引方式不一樣。 陣列通常用 GIN 索引,JSONB 則看資料結構用 GIN 或 BTREE。
效能比較
一般查找任務,陣列會比較快。JSONB 雖然慢一點,但彈性大。如果你只是要查元素(像類型或 ID),陣列會比較有效率:
-- 陣列配 GIN 索引
CREATE INDEX idx_genres ON books USING GIN(genres);
-- 用類型篩書
SELECT * FROM books WHERE genres @> ARRAY['Science Fiction'];
資料存在檢查
JSONB 查 key 的彈性更大:
-- 查有沒有 "genres" 這個 key
SELECT * FROM books_details WHERE details ? 'genres';
-- 查清單裡有沒有某元素
SELECT * FROM books_details WHERE details->'genres' ?| ARRAY['Fantasy', 'Dystopia'];
陣列可以直接查值:
-- 查陣列裡有沒有某元素
SELECT * FROM books WHERE genres @> ARRAY['Fantasy'];
結構彈性
如果資料有複雜巢狀結構,JSONB 超好用:
{
"genres": ["Fantasy", "Adventure"],
"ratings": {"goodreads": 8.5, "amazon": 4.7}
}
陣列要做到這樣就很麻煩,可能還要正規化或加欄位。
總之,陣列跟 JSONB 不是互相競爭,而是各有適合的場景。如果資料像清單——用陣列。如果是複雜、巢狀或混合型態——就選 JSONB。記得效能跟索引也要考慮進去啦!
GO TO FULL VERSION