oracle mysql5.7 Json函數

oracle mysql 5.7.8 以後增長了對json數據格式的函數處理,可更加靈活的在數據庫中操做json數據,如可變屬性、自定義表單等等都使用使用該方式解決。mysql

 

在建立表時,能夠使用「GENERATED ALWAYS AS」 與json中的某個字段關聯,並建立虛擬字段使json字符串也能夠添加索引。sql

 

-- 建立測試json表

CREATE TABLE `test_json` (
  `$json` json NOT NULL,
  `userid` varchar(50) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (json_unquote(json_extract(`$json`,_utf8mb4'$."userid"'))) VIRTUAL,
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `$createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `$updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `name` varchar(60) GENERATED ALWAYS AS ((json_extract(`$json`,_utf8mb4'$."name"') = TRUE)) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `by_userid` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

SET FOREIGN_KEY_CHECKS = 1;

建立json數據庫

json_array(val1,val2,val3...) 建立json數組
json_object(key1,value1,key2,value2...) 建立json對象
json_quote 將json轉成json字符串類型

插入json數據json

-- 方式1 :直接插入json字符串
insert into test_json (id,`$json`) values(1,'{"userid":"1","name":"test name","sex":"男"}');

-- 方式2 :使用json_object
insert into test_json (id,`$json`) values(2,json_object("userid","2","name","test name2","sex","男"));

-- 方式3 :組合使用
insert into test_json (id,`$json`) values(3,json_object("userid","3","name","name3","sex","女","item",json_array("item1","item2","item3")));

 

查詢json數組

json_contains(json_doc,val[,path]) 判斷是否包含某個json值
json_contains_path(json_doc,one_or_all,path[,path]...) 判斷是否有某個路徑
json_extract(json_doc,path[,path]) 提取json值
column->path json_extract 簡潔寫法5.7.9開始支持
column->>path json_unquote(column -> path)

簡潔寫法5.7.13開始支持至關於oracle

JSON_UNQUOTE(JSON_EXTRACT())app

json_keys(json_doc[,path]) 提取json中的鍵值結果爲json數組
json_search(json_doc, one_or_all, search_str[,escape_char[,path]...]) 按給定字符串關鍵字搜索json,返回匹配的路徑

 搜索數組下的多個屬性時可以使用通配符「*」,如獲取數組下對象的某屬性$.item[*].name函數

-- 判斷是否包含某個json值 

-- 方式1
select json_contains(`$json`,'{"name":"test name2"}') from test_json;

-- 方式2 (請注意第二個參數,帶雙引號,官網案例是number類型)
select json_contains(`$json`,'"name3"','$.name') from test_json;



-- 判斷json是否指定路徑,one至少存在一條路徑,all存在全部路徑
select json_contains_path($json,'one','$.item') from test_json;


-- 獲取json值 
-- 方式1
select json_extract(`$json`,'$.item') from test_json;

-- 方式2 簡潔寫法
select `$json` -> '$.item' from test_json;

-- 方式3 簡潔寫法,並取消字符串,可用於select\where\having子句
select `$json` ->> '$.name' from test_json;


-- 獲取json中的key數組
select json_keys($json) from test_json;


-- 獲取json中指定value的json_path
select json_search($json,'one','item2') from test_json;

-- 可以使用通配符
select json_search($json,'one','item%') from test_json;


select json_search($json,'all','2') from test_json;

 

 

修改json性能

json_append (廢棄) 廢棄,MySQL 5.7.9開始更名爲json_array_append
json_array_append(json_doc,path,val[,path,val]...) 末尾添加數組元素,若是原有值是數值或json對 象,則轉成數組後,再添加元素
json_array_insert(json_doc,path,val[,path,val]...) 插入數組元素
json_insert(json_doc,path,val[,path,val]...) 插入值(插入新值,但不替換已經存在的舊值)
json_merge(json_doc,json_doc[,json_doc]...) 合併json數組或對象
json_remove(json_doc,path[,path]...) 刪除json數據
json_replace(json_doc,path,val[,path,val]...) 替換值(只替換已經存在的舊值)
json_set(json_doc,path,val[,path,val]) 設置值(替換舊值,並插入不存在的新值)
json_unquote(val) 去除json字符串的引號,將值轉成string類型
CAST('jsonString' as json) 可將json字符串轉爲json對象格式

 

-- 修改json

-- 只會給有item屬性的json添加

select json_array_append(`$json`,'$.item','new item') from test_json ;


-- 會將對象轉爲數組

select json_array_append(`$json`,'$.name','new item') from test_json ;

-- 向數組指定位置插入,指定的json path必須是數組類型

select json_array_insert(`$json`,'$.item[10]','new item') from test_json ;


-- 添加新屬性,若是沒有新屬性會增長
select json_insert(`$json`,'$.address','北京') from test_json ;

-- 修改原屬性,若是沒有屬性會增長,若是有則不處理

select json_insert(`$json`,'$.name','新名字') from test_json ;

-- 也可向數組中插入
select json_insert(`$json`,'$.item[10]','new item') from test_json ;

-- 合併,根據屬性進行合併,若有相同屬性轉爲數組
select json_merge(`$json`,`$json`) from test_json ;

-- 添加新屬性,合併數組
select json_merge(`$json`,'{"company":"companyName","address":"address","item":["newItem"]}') from test_json ;

-- 刪除指定路徑屬性或數組值
select json_remove(`$json`,'$.item','$.sex') from test_json ;

select json_remove(`$json`,'$.item[0]','$.sex') from test_json ;

-- 替換屬性值
select json_replace(`$json`,'$.sex','男') from test_json ;

-- 替換沒有的屬性不作任何操做
select json_replace(`$json`,'$.address','替換不存在的地址屬性','$.item[20]','4444') from test_json ;

-- 有的屬性作替換值,沒有的作添加
select json_set(`$json`,'$.sex','男','$.address','替換不存在的地址屬性','$.item[20]','4444') from test_json ;




-- 原始獲取json會帶引號

select `$json` -> '$.name' from test_json ;

-- 可去除雙引號
select json_unquote(`$json` -> '$.name') from test_json ;

 

返回json屬性測試

json_depth(json_doc) 返回json文檔的最大深度
json_length(json_doc[,path]) 返回json文檔的長度
json_type(json_val) 返回json值得類型
json_valid()val 判斷是否爲合法json文檔

 

-- json屬性最大深度
select json_depth(`$json`) from test_json ;

-- json對象則是屬性數,數組則是數組長度
select json_length(`$json`) from test_json ;

-- 判斷數據類型

select json_type(`$json`) from test_json ;


select json_type(`$json` -> '$.name') from test_json ;


select json_type(`$json` -> '$.item') from test_json ;

 

json類型
ARRAY JSON數組
BOOLEAN JSON true和false字符串
NULL JSON NULL字符串
數字類型
INTEGER MySQL中 TINYINT, SMALLINT, MEDIUMINT, INT 和 BIGINT 
DOUBLE MySQL中 DOUBLE FLOAT 
DECIMAL DECIMAL 和 NUMERIC 
時間類型
DATETIME MySQL中 DATETIME 和 TIMESTAMP 
DATE MySQL中 DATE 
TIME MySQL中 TIME 
字符串類型
STRING MySQL字符串: CHAR, VARCHAR, TEXT, ENUM, 和 SET
二進制
BLOB MySQL 二進制: BINARY, VARBINARY, BLOB
BIT MySQL中 BIT
其餘
OPAQUE (raw bits)

 

 

 

JSON的存儲結構及具體實現

引用:https://blog.csdn.net/qian_xiaoqian/article/details/53128170


在處理JSON時,MySQL使用的utf8mb4字符集,utf8mb4是utf8和ascii的超集。因爲歷史緣由,這裏utf8並不是是咱們常說的UTF-8 Unicode變長編碼方案,而是MySQL自身定義的utf8編碼方案,最長爲三個字節。具體區別非本文重點,請你們自行Google瞭解。

MySQL在內存中是以DOM的形式表示JSON文檔,並且在MySQL解析某個具體的路徑表達式時,只須要反序列化和解析路徑上的對象,並且速度極快。要弄清楚MySQL是如何作到這些的,咱們就須要瞭解JSON在硬盤上的存儲結構。有個有趣的點是,JSON對象是BLOB的子類,在其基礎上作了特化。

 

使用示意圖更清晰的展現它的結構:

JSON文檔自己是層次化的結構,於是MySQL對JSON存儲也是層次化的。對於每一級對象,存儲的最前面爲存放當前對象的元素個數,以及總體佔的大小。須要注意的是:

  • JSON對象的Key索引(圖中橙色部分)都是排序好的,先按長度排序,長度相同的按照code point排序;Value索引(圖中黃色部分)根據對應的Key的位置依次排列,最後面真實的數據存儲(圖中白色部分)也是如此
  • Key和Value的索引對存儲了對象內的偏移和大小,單個索引的大小固定,能夠經過簡單的算術跳轉到距離爲N的索引
  • 經過MySQL5.7.16源代碼能夠看到,在序列化JSON文檔時,MySQL會動態檢測單個對象的大小,若是小於64KB使用兩個字節的偏移量,不然使用四個字節的偏移量,以節省空間。同時,動態檢查單個對象是不是大對象,會形成對大對象進行兩次解析,源代碼中也指出這是之後須要優化的點
  • 如今受索引中偏移量和存儲大小四個字節大小的限制,單個JSON文檔的大小不能超過4G;單個KEY的大小不能超過兩個字節,即64K
  • 索引存儲對象內的偏移是爲了方便移動,若是某個鍵值被改動,只用修改受影響對象總體的偏移量
  • 索引的大小如今是冗餘信息,由於經過相鄰偏移能夠簡單的獲得存儲大小,主要是爲了應對變長JSON對象值更新,若是長度變小,JSON文檔總體都不用移動,只須要當前對象修改大小
  • 如今MySQL對於變長大小的值沒有預留額外的空間,也就是說若是該值的長度變大,後面的存儲都要受到影響
  • 結合JSON的路徑表達式能夠知道,JSON的搜索操做只用反序列化路徑上涉及到的元素,速度很是快,實現了讀操做的高性能
  • 不過,MySQL對於大型文檔的變長鍵值的更新操做可能會變慢,可能並不適合寫密集的需求
相關文章
相關標籤/搜索