JSON 是目前常使用的資料格式之一,而 PostgreSQL 提供了兩種儲存 JSON 的資料型態,一個是 json
,一個是 jsonb
。
json
和 jsonb
這兩種格式的主要差別在於, json
會儲存原始的 JSON 字串, jsonb
會儲存解析過且轉成二進位格式的 JSON 。jsonb
因為需要解析和轉格式,在 INSERT
的時候速度會比 json
慢,但也因為解析過了,所以在查詢的時候,效能會比 json
好。
另外, jsonb
因為會把欄位是 number
型別的轉換成 PostgreSQL 的 numeric
型別(如下面圖片),所以格式和資料合法性的檢查會比 json
嚴謹。
也因為這樣, jsonb
會拒絕超出 numeric
範圍的數字,但 json
不會,如下面的範例。
CREATE TABLE test_numbers (
js JSON,
jsb JSONB
);
-- JSON 欄位可以成功
INSERT INTO test_numbers (js) VALUES ('{"big_num": 1e1000000000}'); -- 成功
-- JSONB 欄位會報錯
INSERT INTO test_numbers (jsb) VALUES ('{"big_num": 1e1000000000}');
-- 會出現錯誤訊息,例如:
-- ERROR: value overflows numeric format
在索引這一塊, jsonb
的支援比較好, jsonb
可以使用 GIN
這個索引,針對 JSON 中的其中一個欄位去做查詢, json
只能使用 BTRee
和 hash
,但這兩個索引僅拿「整個 JSON 字串」做比對,這對查詢的效能和應用上沒有太大幫助。
而 jsonb
之所以支援 GIN
這個索引,是因為 jsonb
可以使用 @>
和 @?
這類的運算子進行查詢( json
不支援),而 GIN
有支援這些運算子,所以 jsonb
可以使用 GIN
這個索引進行優化。
CREATE TABLE test_json (
id SERIAL PRIMARY KEY,
data_json JSON,
data_jsonb JSONB
);
INSERT INTO test_json (data_json, data_jsonb) VALUES
('{"name": "Alice", "age": 30}', '{"name": "Alice", "age": 30}');
INSERT INTO test_json (data_json, data_jsonb) VALUES
('{"name": "Alice2", "age": 32}', '{"name": "Alice2", "age": 32}');
INSERT INTO test_json (data_json, data_jsonb) VALUES
('{"name": "Alice4", "age": 34}', '{"name": "Alice4", "age": 34}');
以 @>
為例,可以使用 SELECT
的 WHERE
條件去查詢出 jsonb
中的欄位 age
值是32的資料。
如果是 json
的話,PostgreSQL 會噴出錯誤訊息。