《PostgreSQL是不是你的下一個(gè)JSON數(shù)據(jù)庫(kù)?》要點(diǎn):
本文介紹了PostgreSQL是不是你的下一個(gè)JSON數(shù)據(jù)庫(kù)?,希望對(duì)您有用。如果有疑問,可以聯(lián)系我們。
相關(guān)主題:PostgreSQL教程
根據(jù)Betteridge定律(任何頭條的設(shè)問句可以用一個(gè)詞來回答:不是),除非你的JSON數(shù)據(jù)很少修改,并且查詢很多.
最新版的PostgreSQL添加更多對(duì)JSON的支持,我們?cè)?jīng)問過PostgreSQL是否可以替換MongoDB作為JSON數(shù)據(jù)庫(kù),答案顯而易見,但我們更希望的是,啊哈,這個(gè)問題由讀者來問了.
是的,在PostgreSQL 9.4之前的版本也有JSON 數(shù)據(jù)類型了,你可以這樣:
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的原始文本到數(shù)據(jù)庫(kù),包含空白行和鍵順序及重新的鍵,我們來查看下保存的數(shù)據(jù):
>SELECT * FROM justjson; id | doc----+--------------------------------- 1 | { + | "name":"fred", + | "address":{ + | "line1":"52 The Elms", + | "line2":"Elmstreet", + | "postcode":"ES1 1ES" + | } + | }(1 row)
跟保存之前的文本一模一樣,但我們?nèi)钥梢越馕龀鼍唧w的數(shù)據(jù)出來,PostgreSQL提供了一套JSON的操作辦法進(jìn)行查找,例如,我們只要查出address信息,如果做?
select doc->>'address' FROM justjson; ?column?--------------------------------- { + "line1":"52 The Elms", + "line2":"Elmstreet", + "postcode":"ES1 1ES" + }(1 row)
doc字段的 ->> 操作符是查詢JSON對(duì)象的某個(gè)字段并返回文本,用數(shù)字也可以當(dāng)作數(shù)組的索引,但仍返回文本.跟 ->> 類似的還有 -> 操作符,返回不轉(zhuǎn)文本的內(nèi)容,可以用它來導(dǎo)航搜索JSON對(duì)象,如:
select doc->'address'->>'postcode' FROM justjson; ?column?---------- ES1 1ES(1 row)
還有個(gè)更簡(jiǎn)短的寫法來指定搜索路徑,用 #>> 操作符,如夢(mèng):
select doc#>>'{address,postcode}' FROM justjson; ?column?---------- ES1 1ES(1 row)
通過保存完整的JSON數(shù)據(jù)類型可使其跟源數(shù)據(jù)完全一樣并且不會(huì)丟失內(nèi)容,但為堅(jiān)持完全一致也帶來了成本,性能的缺失,而且不能索引...所有,盡管可以很方便的維持一致性和堅(jiān)持JSON文檔,但仍有很大的提升空間,所以引入了JSONB.
JSONB可以將整個(gè)JSON文檔轉(zhuǎn)有層級(jí)的KEY/VALUE數(shù)據(jù)對(duì),所有的空白字符刪除了,重復(fù)鍵只保留最后一次,鍵也沒有排序,而是用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)
可以看到,所有非文本內(nèi)容都消失了,替換成JSON文檔需要的最少格式,這種壓縮方式表示當(dāng)數(shù)據(jù)插入時(shí)會(huì)自動(dòng)格式化,這樣可以減少之后拜訪數(shù)據(jù)分析處理的工作量.
看到鍵值對(duì),JSONB還真有點(diǎn)像PostgreSQL的HSTORE擴(kuò)展,它也可以保留鍵值對(duì),但它是一個(gè)擴(kuò)展,而,JSONB(以及JSON)是在PostgreSQL內(nèi)核的,HSTORE只有一級(jí)層級(jí),但PostgreSQL可以有嵌套的元素,并且,HSTORE只能存字符串,而JSONB還可以存JSON的所數(shù)字類型.
索引,到處用上索引,你不能在PostgreSQL對(duì)JSON類型創(chuàng)建真正的索引,你可以創(chuàng)建表達(dá)式索引(expression indexes),但只限于你想索引的內(nèi)容,例如:
create index justjson_postcode on justjson ((doc->'address'->>'postcode'));
只有郵編(postcode)索引了,其它都沒有索引.
而JSONB,支持GIN索引,一種通用返轉(zhuǎn)索引(Generalized Inverted Index),PostgreSQL提供了另外一套索引操作符來支持,包括 @> 包括JSON,<@ 最包括,? 測(cè)試字符串是否存在,?| 任意字符串是否存在,?& 所有存大的字符串.
有兩類索引可用,默認(rèn)叫 json_ops,它支持所有操作符(譯者:指普通json操作符)和一個(gè)只支持&>操作符的jsonb_path_ops索引(譯者:指索引操作符),默認(rèn)索引給JSON中的每個(gè)鍵值都創(chuàng)建了索引,其實(shí) jsonb_path_ops只創(chuàng)建了一個(gè)比默認(rèn)復(fù)雜的更高壓縮的hash表索引,但默認(rèn)索引擔(dān)任更多操作能力同時(shí)增加了空間本錢.給表添加一些數(shù)據(jù),我們?cè)賮砜纯茨硞€(gè)郵編,如果我們創(chuàng)建了一個(gè)默認(rèn)的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)
可以看出來是順序掃瞄表,如果我們加個(gè)默認(rèn)的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)
搜索性能提升很大,但暗藏了空間的耗費(fèi),例中是41%的數(shù)據(jù)大小,讓我們刪除索引重復(fù)執(zhí)行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)
總成本低了點(diǎn),索引體積小了很多,這是典型的創(chuàng)建索引速度和空間平衡的辦法,但比順序掃瞄性能高很多.
如果你經(jīng)常更新你的JSON文檔,回答是否定的,PostgreSQL最擅長(zhǎng)的是存儲(chǔ)和攻取JSON文檔及他們的字段,但盡管如此你可以取出單個(gè)字段,你也不能更新單個(gè)字段;實(shí)際上你可以,將整個(gè)JSON解析出來,添加新的字段再寫回,讓JSON分析器處理重復(fù),但你很明顯不想依賴這個(gè).
如果你的主要數(shù)據(jù)用關(guān)系數(shù)據(jù)庫(kù)用得很好,JSON數(shù)據(jù)只是一群補(bǔ)充(靜態(tài)數(shù)據(jù)),那么用PostgreSQL就可以了,而且用JSONB表現(xiàn)和索引能力將更高效.另外,如果你的數(shù)據(jù)模型是可變內(nèi)容的集合,那么你可能會(huì)尋找一樣主流工業(yè)級(jí)的json文檔數(shù)據(jù)庫(kù)如MongoDB或RethinkDB.
維易PHP培訓(xùn)學(xué)院每天發(fā)布《PostgreSQL是不是你的下一個(gè)JSON數(shù)據(jù)庫(kù)?》等實(shí)戰(zhàn)技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培養(yǎng)人才。
轉(zhuǎn)載請(qǐng)注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/9196.html