《PostgreSQL是不是你的下一個JSON數據庫?》要點:
本文介紹了PostgreSQL是不是你的下一個JSON數據庫?,希望對您有用。如果有疑問,可以聯系我們。
相關主題:PostgreSQL教程
根據Betteridge定律(任何頭條的設問句可以用一個詞來回答:不是),除非你的JSON數據很少修改,并且查詢很多.
最新版的PostgreSQL添加更多對JSON的支持,我們曾經問過PostgreSQL是否可以替換MongoDB作為JSON數據庫,答案顯而易見,但我們更希望的是,啊哈,這個問題由讀者來問了.
是的,在PostgreSQL 9.4之前的版本也有JSON 數據類型了,你可以這樣:
CREATE TABLE justjson ( id INTEGER, doc JSON)>INSERT INTO justjson VALUES ( 1, '{ "name":"fred", "address":{ "line1":"52 The Elms", "line2":"Elmstreet", "postcode":"ES1 1ES" } }');
保存了JSON的原始文本到數據庫,包含空白行和鍵順序及重新的鍵,我們來查看下保存的數據:
>SELECT * FROM justjson; id | doc----+--------------------------------- 1 | { + | "name":"fred", + | "address":{ + | "line1":"52 The Elms", + | "line2":"Elmstreet", + | "postcode":"ES1 1ES" + | } + | }(1 row)
跟保存之前的文本一模一樣,但我們仍可以解析出具體的數據出來,PostgreSQL提供了一套JSON的操作辦法進行查找,例如,我們只要查出address信息,如果做?
select doc->>'address' FROM justjson; ?column?--------------------------------- { + "line1":"52 The Elms", + "line2":"Elmstreet", + "postcode":"ES1 1ES" + }(1 row)
doc字段的 ->> 操作符是查詢JSON對象的某個字段并返回文本,用數字也可以當作數組的索引,但仍返回文本.跟 ->> 類似的還有 -> 操作符,返回不轉文本的內容,可以用它來導航搜索JSON對象,如:
select doc->'address'->>'postcode' FROM justjson; ?column?---------- ES1 1ES(1 row)
還有個更簡短的寫法來指定搜索路徑,用 #>> 操作符,如夢:
select doc#>>'{address,postcode}' FROM justjson; ?column?---------- ES1 1ES(1 row)
通過保存完整的JSON數據類型可使其跟源數據完全一樣并且不會丟失內容,但為堅持完全一致也帶來了成本,性能的缺失,而且不能索引...所有,盡管可以很方便的維持一致性和堅持JSON文檔,但仍有很大的提升空間,所以引入了JSONB.
JSONB可以將整個JSON文檔轉有層級的KEY/VALUE數據對,所有的空白字符刪除了,重復鍵只保留最后一次,鍵也沒有排序,而是用HASH來保留了,上面的例子中用JSONB的版本的話,看來起類似這樣:
>CREATE TABLE justjsonb ( id INTEGER, doc JSONB)>INSERT INTO justjsonb VALUES ( 1, '{ "name":"fred", "address":{ "line1":"52 The Elms", "line2":"Elmstreet", "postcode":"ES1 1ES" } }');>SELECT * FROM justjsonb; id | doc----+---------------------------------------------------------------------------------------------------- 1 | {"name": "fred", "address": {"line1": "52 The Elms", "line2": "Elmstreet", "postcode": "ES1 1ES"}}(1 row)
可以看到,所有非文本內容都消失了,替換成JSON文檔需要的最少格式,這種壓縮方式表示當數據插入時會自動格式化,這樣可以減少之后拜訪數據分析處理的工作量.
看到鍵值對,JSONB還真有點像PostgreSQL的HSTORE擴展,它也可以保留鍵值對,但它是一個擴展,而,JSONB(以及JSON)是在PostgreSQL內核的,HSTORE只有一級層級,但PostgreSQL可以有嵌套的元素,并且,HSTORE只能存字符串,而JSONB還可以存JSON的所數字類型.
索引,到處用上索引,你不能在PostgreSQL對JSON類型創建真正的索引,你可以創建表達式索引(expression indexes),但只限于你想索引的內容,例如:
create index justjson_postcode on justjson ((doc->'address'->>'postcode'));
只有郵編(postcode)索引了,其它都沒有索引.
而JSONB,支持GIN索引,一種通用返轉索引(Generalized Inverted Index),PostgreSQL提供了另外一套索引操作符來支持,包括 @> 包括JSON,<@ 最包括,? 測試字符串是否存在,?| 任意字符串是否存在,?& 所有存大的字符串.
有兩類索引可用,默認叫 json_ops,它支持所有操作符(譯者:指普通json操作符)和一個只支持&>操作符的jsonb_path_ops索引(譯者:指索引操作符),默認索引給JSON中的每個鍵值都創建了索引,其實 jsonb_path_ops只創建了一個比默認復雜的更高壓縮的hash表索引,但默認索引擔任更多操作能力同時增加了空間本錢.給表添加一些數據,我們再來看看某個郵編,如果我們創建了一個默認的GIN JSON索引然后查詢:
explain select * from justjsonb where doc @> '{ "address": { "postcode":"HA36CC" } }'; QUERY PLAN----------------------------------------------------------------- Seq Scan on justjsonb (cost=0.00..3171.14 rows=100 {"address": {"postcode": "HA36CC"}}'::jsonb)(2 rows)
可以看出來是順序掃瞄表,如果我們加個默認的JSON GIN索引后再看看有什么不同?
> create index justjsonb_gin on justjsonb using gin (doc);> explain select * from justjsonb where doc @> '{ "address": { "postcode":"HA36CC" } }'; QUERY PLAN------------------------------------------------------------------------------- Bitmap Heap Scan on justjsonb (cost=40.78..367.62 rows=100 {"address": {"postcode": "HA36CC"}}'::jsonb) -> Bitmap Index Scan on justjsonb_gin (cost=0.00..40.75 rows=100 {"address": {"postcode": "HA36CC"}}'::jsonb)(4 rows)
搜索性能提升很大,但暗藏了空間的耗費,例中是41%的數據大小,讓我們刪除索引重復執行jsonb_path_ops GIN索引.
> create index justjsonb_gin on justjsonb using gin (doc jsonb_path_ops);> explain select * from justjsonb where doc @> '{ "address": { "postcode":"HA36CC" } }'; QUERY PLAN------------------------------------------------------------------------------- Bitmap Heap Scan on justjsonb (cost=16.78..343.62 rows=100 {"address": {"postcode": "HA36CC"}}'::jsonb) -> Bitmap Index Scan on justjsonb_gin (cost=0.00..16.75 rows=100 {"address": {"postcode": "HA36CC"}}'::jsonb)(4 rows)
總成本低了點,索引體積小了很多,這是典型的創建索引速度和空間平衡的辦法,但比順序掃瞄性能高很多.
如果你經常更新你的JSON文檔,回答是否定的,PostgreSQL最擅長的是存儲和攻取JSON文檔及他們的字段,但盡管如此你可以取出單個字段,你也不能更新單個字段;實際上你可以,將整個JSON解析出來,添加新的字段再寫回,讓JSON分析器處理重復,但你很明顯不想依賴這個.
如果你的主要數據用關系數據庫用得很好,JSON數據只是一群補充(靜態數據),那么用PostgreSQL就可以了,而且用JSONB表現和索引能力將更高效.另外,如果你的數據模型是可變內容的集合,那么你可能會尋找一樣主流工業級的json文檔數據庫如MongoDB或RethinkDB.
維易PHP培訓學院每天發布《PostgreSQL是不是你的下一個JSON數據庫?》等實戰技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培養人才。