在 PostgreSQL 處理 JSON 資料超強大,但就像所有工具一樣,用的時候要小心。就算一點小錯誤,也可能讓你的查詢變成大謎題。 今天我們又要來聊聊在 PostgreSQL 處理 JSON 跟 JSONB 時常見的錯誤,還有怎麼避免它們。
問題 1:用 JSON 取代 JSONB
很多新手會誤以為 JSON 是存 JSON 資料最好的選擇。但其實在 PostgreSQL 裡,JSON 是用純文字存資料,這會讓你在搜尋或篩選時效能變超差。
錯誤範例:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSON
);
INSERT INTO products (details) VALUES ('{"name": "Laptop", "price": 1000}');
INSERT INTO products (details) VALUES ('{"name": "Laptop", "price": 1000}');
如果你想用 key (price) 來篩選,速度會比 JSONB 慢很多。
怎麼修正: 如果你打算常常篩選或查資料,直接用 JSONB 吧。
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSONB
);
問題 2:JSONB 沒加 index
JSONB 超強大沒錯,但如果沒加 index,複雜查詢時效能會掉超多。
錯誤範例:假設我們有個欄位 details,裡面塞了一堆 JSON 物件:
SELECT * FROM products WHERE details->>'name' = 'Laptop';
如果沒加 index,server 會 full table scan(整張表慢慢找),超浪費時間。
怎麼修正: 加個 GIN index,查 key 會快很多:
CREATE INDEX idx_details_name ON products USING gin (details jsonb_path_ops);
問題 3:抓巢狀資料時出錯
從巢狀物件或 array 抓資料很容易搞混,尤其你還不熟 -> 跟 ->> 這兩個 operator 的差別時。
錯誤範例:
SELECT details->'price' FROM products;
這個查詢會回傳 JSON 格式的值,不是純字串("1000" 而不是 1000)。如果你只想要值,要用 ->>:
SELECT details->>'price' FROM products;
問題 4:operator 用錯
你可能看過 @> 這個 operator,覺得:「看起來很酷耶,來用用看!」但如果你不懂它怎麼運作,結果可能會很奇怪。
錯誤範例:
SELECT * FROM products WHERE details @> '{"price": 1000}';
這個查詢只有在 price 是數字時才會 work。如果值是字串 "1000",這查詢會找不到東西。
怎麼修正: 記得注意 JSON 裡的資料型別:
SELECT * FROM products WHERE details->>'price' = '1000';
問題 5:超大的 JSON 物件
沒優化就直接存很大的 JSON 物件,查詢速度會慢到爆。而且就算你只想改 JSONB 裡一小段資料,也要整個物件都處理一次。
怎麼修正: 如果有些 key 常常用,直接拉出來變成 table 的欄位。例如:
ALTER TABLE products ADD COLUMN price NUMERIC;
UPDATE products SET price = (details->>'price')::NUMERIC;
這樣你就可以有效率地篩選跟排序,不用每次都拆 JSONB。
問題 6:每次改資料都重建整個物件
用 jsonb_set() 或 jsonb_insert() 這種 function 時,PostgreSQL 會重建一個全新的 JSONB 物件,這對效能來說很傷。
怎麼修正: 盡量減少 JSONB 的更新次數。例如,不要一直改同一個物件,把所有變動合併成一個 query:
UPDATE products
SET details = jsonb_set(details, '{price}', '1500'::jsonb);
問題 7:搞不懂 array 結構
JSONB 裡的 array 也要小心用。假設你有個 array:
{
"tags": ["electronics", "laptop", "sale"]
}
你想查有沒有 "laptop" 這個 tag。如果 operator @> 用錯,可能查不到,因為它要的是 array,不是單一字串。
錯誤範例:
SELECT * FROM products WHERE details->'tags' @> '"laptop"';
怎麼修正: @> operator 要用正確格式:
SELECT * FROM products WHERE details->'tags' @> '["laptop"]';
避免錯誤的小建議
想在用 JSONB 時少踩雷,可以照這些建議做:
選對資料型別。 如果你資料量大又常常要篩選,記得用 JSONB,不要用 JSON。
加 index。 如果常查某些 key,記得加對應的 index(像 GIN)。
插入前先檢查資料。 用 validation function 先檢查資料結構:
DO $$
BEGIN
IF jsonb_typeof('{"price": 1000}'::jsonb->'price') IS DISTINCT FROM 'number' THEN
RAISE EXCEPTION 'Price 必須是數字';
END IF;
END $$;
優化資料結構。 如果有些 key 特別常用,直接拉出來變成 table 欄位。
多看 operator 跟 function。 仔細讀 PostgreSQL 官方文件,搞懂 ->、->>、@>、?| 等等的差別。
JSON 跟 JSONB 可以讓你很彈性地處理複雜資料。重點是選對工具、避開常見錯誤,這樣你的 code 就又快又好維護啦!
GO TO FULL VERSION