MySQL数据库的JSON数据类型详解
文章目錄
- JSON 數據類型意義
- 存儲JSON串
- 修改JSON串中指定字段的值
- 查詢 JSON 串中的數據
- 查詢 JSON 串中指定字段的值
- 特殊語法
- 精確查詢
- 嵌套精確查詢
- 模糊查詢
- 優化 JSON 查詢
- 處理 JSON 數據的常用函數
- JSON_CONTAINS_PATH
- JSON_PRETTY
- 總結
- 參考資料
JSON 數據類型意義
其實,沒有JSON數據類型的支持,我們一樣可以通過varchar類型或者text等類型來保存這一格式的數據,但是,為什么還要專門增加這一數據格式的支持呢?其中肯定有較varchar或者text來存儲此類型更優越的地方。
1.保證了 JSON 數據類型的強校驗,JSON 數據列會自動校驗存入此列的內容是否符合 JSON 格式,非正常格式則報錯,而 varchar 類型和 text 等類型本身是不存在這種機制的。
2.MySQL 同時提供了一組操作 JSON 類型數據的內置函數。
3.更優化的存儲格式,存儲在 JSON 列中的 JSON 數據會被轉成內部特定的存儲格式,允許快速讀取。
4.基于 JSON 格式的特征,支持修改指定的字段值。
存儲JSON串
insert into commodity(commodity_id,title,current_selling_price,attributes) values (9,'小米手機',2000,'{"specValueId":"3845862150911746064","specValue":"深紅色","specValueType":"紅色系","specValueTypeId":"3845862150911746056","specId":"3845862150911746061","specName":"xx顏色","specType":"顏色","extdata1":"rgba(255, 9, 9, 1)","extdata2":"http://localhost:8080/123.png"}');這里需要提醒的是:
JSON 類型的列存儲的數據要么是 NULL,要么必須是 JSON 格式數據,否則會報錯。
JSON 數據類型默認值只能是 NULL。
修改JSON串中指定字段的值
可以使用兩個內置函數來修改JSON串中指定字段的值,示例如下:
# 將列attributes中的json串中的字段specValue的值設置為‘綠色’ update commodity set attributes = JSON_SET(attributes,'$.specValue','綠色') where title like '%手機'; # 將列attributes中的json串中的字段specValue的值替換為‘yellow’ update commodity set attributes = JSON_REPLACE(attributes,'$.specValue','yellow') where title like '%手機';查詢 JSON 串中的數據
查詢 JSON 串中指定字段的值
select JSON_EXTRACT(attributes,'$.specValue') from commodity where commodity_id = 9;這里要特別注意了,讀取json串中指定字段的值,如果該值是字符串則會把雙引號也讀取出來,可以使用函數 JSON_UNQUOTE() 去掉雙引號:
select json_unquote(JSON_EXTRACT(attributes,'$.specValue')) from commodity where commodity_id = 9;特殊語法
查詢列 attributes 中的 json 串中的字段 specValue 的值,可以使用下面兩種查詢語句:
select attributes->>'$.specValue' from commodity;或者
select attributes->'$.specValue' from commodity;精確查詢
假設有個名為 player 的表,有個名為 remarks 的 JSON 類型的列,存儲的數據格式如下:
{"name":"lisi","age":39,"address":{"city":"rizhao","region":"lanshan"}}查詢 remarks 列中的json串的name字段的值為“zhangsan”的所有記錄:
SELECT * FROM `player` WHERE JSON_EXTRACT(`Remarks`, '$.name') = 'zhangsan';或者
SELECT * FROM `player` WHERE JSON_CONTAINS(Remarks,JSON_OBJECT('name','zhangsan'));或者
select * from player where json_contains(remarks,'"zhangsan"','$.name');嵌套精確查詢
查詢用戶居住城市是日照的所有記錄:
SELECT * FROM `player` WHERE JSON_EXTRACT(`Remarks`, '$.address.city') = 'rizhao';模糊查詢
查詢列 remarks 中的json串中的字段name的值中包含“zhangsan”的所有記錄:
SELECT * FROM `player` WHERE JSON_EXTRACT(`Remarks`, '$.name') LIKE '%zhangsan%';查詢列 remarks 中的 json 串中的字段 age 的值大于等于 25 的所有記錄:
SELECT * FROM `player` WHERE JSON_EXTRACT(`Remarks`, '$.age') >= 25;優化 JSON 查詢
找出顏色是“綠色”的商品:
select * from commodity where JSON_EXTRACT(attributes,'$.specValue') = 'yellow';查看執行計劃:
explain select * from commodity where JSON_EXTRACT(attributes,'$.specValue') = 'yellow';
從執行計劃可以看到,查詢類型是全表掃描,這樣的效率是很低的,那么如何優化呢?
按照過往的思路,我們只要設計合理的索引就能避免全表掃描,但是 JSON 列不能創建索引,官方給出的方法是:基于JSON 創建一個生成列(Generated Column),然后基于生成列創建索引,從而達到對 JSON 類型列加索引的效果。
生成列的值在插入數據時不需要設置,MySQL 會根據生成列關聯的表達式自動計算填充。
我們分三步進行演示。
第一步,創建生成列:
生成列 v_spec_value 的值根據表達式 attributes->'$.specValue' 自動計算填充。
第二步,為 v_spec_value 創建索引:
alter table commodity add index idx_spec_value (v_spec_value);第三步,使用索引字段來查詢:
select * from commodity where v_spec_value = '"yellow"';在查看執行計劃:
explain select * from commodity where v_spec_value = '"yellow"';有個疑問:根據表達式獲取JSON串中指定字段值,如果是字符串類型的,會把雙引號也獲取到,導致存儲時也會將雙引號一起存進去,這個問題如何解決呢?
處理 JSON 數據的常用函數
JSON_CONTAINS_PATH
判斷 JSON 串中是否有指定的字段。
查詢列attributes 中的 json 串中含有字段 specValue的記錄數量:
SELECT count(*), JSON_CONTAINS_PATH(attributes, 'all', '$.specValue') cp FROM commodity GROUP BY cp;查詢結果如下:
mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}'; mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e'); -- 指定參數one,表示只要json串中含有至少一個指定字段,則返回1,否則返回0 +---------------------------------------------+ | JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e') | +---------------------------------------------+ | 1 | +---------------------------------------------+ mysql> SELECT JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.e'); -- 指定參數all,表示json串中必須含有全部指定的字段才會返回1,否則返回0 +---------------------------------------------+ | JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.e') | +---------------------------------------------+ | 0 | +---------------------------------------------+ mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.c.d'); +----------------------------------------+ | JSON_CONTAINS_PATH(@j, 'one', '$.c.d') | +----------------------------------------+ | 1 | +----------------------------------------+ mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a.d'); +----------------------------------------+ | JSON_CONTAINS_PATH(@j, 'one', '$.a.d') | +----------------------------------------+ | 0 | +----------------------------------------+JSON_PRETTY
返回格式化的 json 數據:
select json_pretty(attributes) from commodity;格式化后,顯示成這樣:
{"specId": "3845862150911746061","extdata1": "rgba(255, 9, 9, 1)","extdata2": "http://localhost:8080/123.png","specName": "xx顏色","specType": "顏色","specValue": "yellow","specValueId": "3845862150911746064","specValueType": "紅色系","specValueTypeId": "3845862150911746056" }總結
JSON 類型是 MySQL 5.7 版本新增的數據類型,用好 JSON 數據類型可以有效解決很多業務中實際問題。最后,我總結下今天的重點內容: 使用 JSON 數據類型,推薦用 MySQL 8.0.17 以上的版本,性能更好,同時也支持 Multi-Valued Indexes。
1.JSON 數據類型的好處是無須預先定義列,數據本身就具有很好的描述性;
2.不要將有明顯關系型的數據用 JSON 存儲,如用戶余額、用戶姓名、用戶身份證等,這些都是每個用戶必須包含的數據;
3.JSON 數據類型推薦用于存儲不經常更新的靜態數據。
參考資料
1.https://dev.mysql.com/doc/refman/5.7/en/json-functions.html
2.https://zhuanlan.zhihu.com/p/31823258
3.https://dasini.net/blog/2018/07/23/30-mins-with-mysql-json-functions/
總結
以上是生活随笔為你收集整理的MySQL数据库的JSON数据类型详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首都师范大学计算机调剂被拒绝,首都师范大
- 下一篇: android 云端数据库更新到本地