PostgreSQL中json數據類型詳解
前言
JSON(JavaScript Object Notation)是一種輕量級的數據交換格式。它基于 ECMAScript(European Computer Manufacturers Association, 歐洲計算機協會制定的js規(guī)范)的一個子集,采用完全獨立于編程語言的文本格式來存儲和表示數據。簡潔和清晰的層次結構使得 JSON 成為理想的數據交換語言。 易于人閱讀和編寫,同時也易于機器解析和生成,并有效地提升網絡傳輸效率。其實JSON作為一種數據規(guī)范和標準,在用于接口交換,系統(tǒng)配置,數據存儲方面擁有得天獨厚的一席之地。
在存儲技術已經高速發(fā)達的今天,對于json數據的存儲和使用,有多重方式。比如在緩存界的一哥Redis,文檔數據庫的佼佼者Mongodb等等。上述兩者的基礎數據結構也是JSON,基于json豐富的開發(fā)接口和支持。
隨著技術和業(yè)務的發(fā)展,除了上述兩者之外,許多傳統(tǒng)的關系型數據庫,如MySQL、PostgreSQL(以下簡稱PG)等等都開始支持json數據的存儲和高效查詢。在不增加額外的技術棧學習成本之下,基于統(tǒng)一的數據庫庫知識來滿足日常的業(yè)務需求,也是一種合理的技術選型(滿足了日常業(yè)務即可)。本文重點講述在PG中關于json類型的介紹,json和jsonb的區(qū)別,json和jsonb的基本操作、輸出區(qū)別、包含測試等內容,讓各位對json類型有一個基本直觀的認識。理解最基礎的數據庫操作。
一、PG數據庫中JSON的類型
json數據也可以被存儲為text,但是 與text數據類型相比,JSON 數據類型的優(yōu)勢在于能強制要求每個被存儲的值符合 JSON 規(guī)則。也有很多 JSON 相關的函 數和操作符可以用于存儲在這些數據類型中的數據?;趖ext類型的數據,無法直接利用數據庫的查詢技術來提高查詢效率。而且需要在應用程序中進行相關的轉換。眾所周知,PostgreSQL 提供存儲JSON數據的兩種類型:json 和 jsonb。
1、json和jsonb的區(qū)別
json 和 jsonb數據類型接受幾乎完全相同的值集合作為輸入。 主要的實際區(qū)別之一是效率。json數據類型存儲輸入文本的精準拷貝,處理函數必須在每 次執(zhí)行時必須重新解析該數據。而jsonb數據被存儲在一種分解好的 二進制格式中,它在輸入時要稍慢一些,因為需要做附加的轉換。但是 jsonb在處理時要快很多,因為不需要解析。jsonb也支 持索引,這也是一個令人矚目的優(yōu)勢(言外之意,json類型對索引程度不是特別友好)。
由于json類型存儲的是輸入文本的準確拷貝,其中可能會保留在語法 上不明顯的、存在于記號之間的空格,還有 JSON 對象內部的鍵的順序。還有, 如果一個值中的 JSON 對象包含同一個鍵超過一次,所有的鍵/值對都會被保留( 處理函數會把最后的值當作有效值)。相反,jsonb不保留空格、不 保留對象鍵的順序并且不保留重復的對象鍵。如果在輸入中指定了重復的鍵,只有 最后一個值會被保留。
2、項目開發(fā)中的選擇
從數據插入更新處理速度上,json>jsonb。在數據查詢性能上jsonb>json。在數據的整體空間占用上,json>jsonb。
因此,通常在一般的技術開發(fā)過程中,除非有特別特殊的需要(歷史遺留問題等),大多數應用應該 更愿意把 JSON 數據存儲為jsonb(通過json函數和函數索引的加持下,jsonb的查詢能力得到了大大的增強)。
3、json數據類型
在pg中的json數據類型可以分為:String,Number,boolean,Null。下面給出一個表格,是關于json的基本數據類型和pg數據類型的一個對比和對照。
| JSON類型 | PG數據類型 | 說明 |
| String | text | 不允許\u0000,如果數據庫編碼不是 UTF8,非 ASCII Unicode 轉義也是這樣 |
| Number | Number | 不允許NaN 和 infinity值 |
| Boolean | boolean | 只接受小寫true和false拼寫 |
| NULL | 無 | SQL NULL是一個不同的概念 |
這里關于編碼有一個需要解釋的地方,就是Unicode的轉義問題。這里涉及到數據庫在創(chuàng)建的時候是不是使用utf-8的編碼存儲。在json類型的輸入函數中,不管數據庫 編碼如何都允許 Unicode 轉義,并且只檢查語法正確性(即,跟在\u 后面的四個十六進制位)。但是,jsonb的輸入函數更加嚴格:它不允 許非 ASCII 字符的 Unicode 轉義(高于U+007F的那些),除非數據 庫編碼是 UTF8。jsonb類型也拒絕\u0000(因為 PostgreSQL的text類型無法表示 它),并且它堅持使用 Unicode 代理對來標記位于 Unicode 基本多語言平面之外 的字符是正確的。合法的 Unicode 轉義會被轉換成等價的 ASCII 或 UTF8 字符進 行存儲,這包括把代理對折疊成一個單一字符。在把文本 JSON 輸入轉換成jsonb時,RFC 7159描述 的基本類型會被有效地映射到原生的 PostgreSQL類型(如 上表描述)。因此,在合法 jsonb數據的組成上有一些次要額外約束,它們不適合 json類型和抽象意義上的 JSON,這些約束對應于有關哪些東西不 能被底層數據類型表示的限制。尤其是,jsonb將拒絕位于 PostgreSQL numeric數據類型范 圍之外的數字,而json則不會。不過,實際上這類問題更可能發(fā)生在其他實 現中,因為把 JSON 的number基本類型表示為 IEEE 754 雙精度浮點 是很常見的(這也是RFC 7159 明確期待和允許的)。當在這類系 統(tǒng)間使用 JSON 作為一種交換格式時,應該考慮丟失數字精度的風險。
二、PG中json的簡單操作
1、基礎json數據操作
-- 簡單標量/基本值
-- 基本值可以是數字、帶引號的字符串、true、false或者null
SELECT '5'::json;
-- 有零個或者更多元素的數組(元素不需要為同一類型)
SELECT '[1, 2, "foo", null]'::json;
-- 包含鍵值對的對象
-- 注意對象鍵必須總是帶引號的字符串
SELECT '{"name": "張三", "age": 39, "active": false,"sex":"男"}'::json;
-- 數組和對象可以被任意嵌套
SELECT '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'::json;2、json和jsonb輸出對比
SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json;
json
-------------------------------------------------
{"bar": "baz", "balance": 7.77, "active":false}
(1 row)
SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb;
jsonb
--------------------------------------------------
{"bar": "baz", "active": false, "balance": 7.77}
(1 row)通過這里輸出可以看到,將目標對象作為json輸出時,輸出結果和輸入基本保持一致。 對于第二條語句而言,內容上似乎沒有什么太大的變化,但是輸出結果的順序與第一條有明顯的區(qū)別。
再來看一組有意思的輸出,依然是關于jsonb和json的number結果的展示。
SELECT '{"reading": 1.230e-5}'::json, '{"reading": 1.230e-5}'::jsonb;
json | jsonb
-----------------------+-------------------------
{"reading": 1.230e-5} | {"reading": 0.00001230}
(1 row)很明顯的區(qū)別是jsonb被數據庫的執(zhí)行引擎給優(yōu)化了,展示結果與json也不同。
3、jsonb包含測試
在很多的場景中,我們會使用API對兩個json進行是否包含的判斷,因為在json類型中,使用包含判斷也是比較耗費時間的,在pg數據庫中,天然提供了數據庫層的包含函數,以此來提高查詢匹配能力。在jsonb的查詢中,使用@>進行包含的查詢操作。
-- 右邊具有一個單一鍵值對的對象被包含在左邊的對象中:
SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb;
-- 右邊的數組不會被認為包含在左邊的數組中,
-- 即使其中嵌入了一個相似的數組:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb; -- 得到假
-- 但是如果同樣也有嵌套,包含就成立:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;
-- 類似的,這個例子也不會被認為是包含:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb; -- 得到假
-- 包含一個頂層鍵和一個空對象:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;總結
以上就是本文的基本內容,本文首先介紹了通用的json相關知識,然后重點講述在PG中關于json類型的介紹,json和jsonb的區(qū)別,最后以案例的形式詳細說明json和jsonb的基本操作、輸出區(qū)別、包含測試等內容,讓各位對json類型有一個基本直觀的認識,理解最基礎的數據庫操作。
到此這篇關于PostgreSQL中json數據類型的文章就介紹到這了,更多相關PostgreSQL json類型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

