根據Betteridge定律(任何頭條的設問句能夠用一個詞來回答:不是),除非你的JSON數據不多修改,而且查詢不少。
html
最新版的PostgreSQL添加更多對JSON的支持,咱們曾經問過PostgreSQL是否能夠替換MongoDB做爲JSON數據庫,答案顯而易見,但咱們更但願的是,啊哈,這個問題由讀者來問了。sql
是的,在PostgreSQL 9.4以前的版本也有JSON 數據類型了,你能夠這樣:mongodb
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信息,若是作?express
select doc->>'address' FROM justjson; ?column? --------------------------------- { + "line1":"52 The Elms", + "line2":"Elmstreet", + "postcode":"ES1 1ES" + } (1 row)
doc字段的 ->> 操做符是查詢JSON對象的某個字段並返回文本,用數字也能夠看成數組的索引,但仍返回文本。跟 ->> 相似的還有 -> 操做符,返回不轉文本的內容,能夠用它來導航搜索JSON對象,如:json
select doc->'address'->>'postcode' FROM justjson; ?column? ---------- ES1 1ES (1 row)
還有個更簡短的寫法來指定搜索路徑,用 #>> 操做符,如夢:c#
select doc#>>'{address,postcode}' FROM justjson; ?column? ---------- ES1 1ES (1 row)
經過保存完整的JSON數據類型可以使其跟源數據徹底同樣而且不會丟失內容,但爲保持徹底一致也帶來了成本,性能的缺失,並且不能索引...全部,儘管能夠很方便的維持一致性和保持JSON文檔,但仍有很大的提高空間,因此引入了JSONB。數組
JSONB能夠將整個JSON文檔轉有層級的KEY/VALUE數據對,全部的空白字符刪除了,重複鍵只保留最後一次,鍵也沒有排序,而是用HASH來保存了,上面的例子中用JSONB的版本的話,看來起相似這樣:post
>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。
參考
PostgreSQL vs MongoDB http://my.oschina.net/Suregogo/blog/358277
Query JSON in PostgreSQL http://schinckel.net/2014/05/25/querying-json-in-postgres/
原文: https://www.compose.io/articles/is-postgresql-your-next-json-database/
<譯:朱淦 350050183@qq.com 2015.8.9>