在我們梳理的開發規範裡面,明確規定對於lob型別的使用原則只有乙個,那就是盡量不要使用。但是很明顯,開發同學走到了我們前面,如果你碰到開發同學使用json資料型別該怎麼建議呢,至少在建議前我們也得了解下json型別的使用要領吧。
在說json型別之前,我們來說下在沒有json資料型別之前我們是怎麼處理一些複雜的資料對映的。
對於開發語言還是資料庫技術來說,字串處理總是很有魅力的乙個特性,所以我會花更多的精力在這個上面。比如之前做了乙個簡單的測試。裡面用到了一些看起來複雜的字串處理函式find_in_set,substring_index等。
問題的背景是我們為乙個表建立了兩個列col1,col2,然後插入一些屬性值。即col1裡面的屬性值和col2裡面的屬性值是對應的。或者換句話來說,col1裡面存放的是key,col2存放的是value.
create table test1 ( col1 varchar(100),col2 varchar(100));
insert test1 select
'26,59,6', '1502.5,1690,2276.77' union all select
'59,33,6', '3502.1,1020,2276.77' union all select
'22,8,59', '1332.6,2900,1520.77';
寫入資料之後,表裡的資料分布是這樣的:
mysql> select *from test1;
| col1 | col2 |
| 26,59,6 | 1502.5,1690,2276.77 |
| 59,33,6 | 3502.1,1020,2276.77 |
| 22,8,59 | 1332.6,2900,1520.77 |
3 rows in set (0.00 sec)
現在我們如果要做乙個資料查詢,把key是59的value值查出來,然後需要value值小於2000.
如果使用sql,可能會是這樣的解決方法。
mysql> select col1,col2
-> from (select *,find_in_set('59',col1) as rn from test1) k
-> where substring_index(concat(',',substring_index(col2,',',rn)),',',-1)
-> <'2000';
| col1 | col2 |
| 26,59,6 | 1502.5,1690,2276.77 |
| 22,8,59 | 1332.6,2900,1520.77 |
2 rows in set (0.00 sec)
當然可能你會有更好的解決方案,但是看起來似乎也不是乙個很好的解決方法,比如這種設計中,如果要加乙個字段,那簡直就是災難性的。
在這種模式下,使用json其實也是一種改進思路,當然這是在mysql 5.7之後了。
我們建立的表為json_test,然後插入兩行記錄。
create table json_test ( uid int auto_increment,data json,primary key(uid))engine=innodb;
insert into json_test values (null,'');
insert into json_test values (null,'');
現在到了json發揮作用的時候了,如果要查詢出資料,我們可以使用類似引用的語法"->"即可。所以我們可以把資料很方便的解析出來。
mysql> select data->"$.name" as name,(data->"$.location") from json_test group by name;
| name | (data->"$.location") |
| "jeanron" | "beijing" |
| "jianrong" | "gansu" |
2 rows in set (0.00 sec)
在這種模式下,上面的第乙個難題其實就完全可以使用這種方式來解決了。
在這個基礎上我們更近一步,在5.7裡面還有輔助的特性虛擬列和相關的索引,可以提高我們查詢的效率。我們新增乙個虛擬列user_name.
alter table json_test add user_name varchar(128) generated always as(json_extract(data,'$.name')) virtual;
使用desc檢視,其實可以看到user_name的屬性是相對特殊的。
mysql> desc json_test;
| field | type | null | key | default | extra |
| uid | int(11) | no | pri | null | auto_increment |
| data | json | yes | | null | |
| user_name | varchar(128) | yes | mul | null | virtual generated |
3 rows in set (0.00 sec)
然後在這個基礎上新增乙個索引。
alter table json_test add index idx_username(user_name);
使用show create table的方式檢視建表ddl可以清晰的看到是有乙個輔助索引。
create table `json_test` (
`uid` int(11) not null auto_increment,
`data` json default null,
`user_name` varchar(128) generated always as (json_extract(`data`,'$.name')) virtual,
primary key (`uid`),
key `idx_username` (`user_name`)
) engine=innodb auto_increment=3 default charset=utf8 |
然後我們再次查詢,注意在這裡的user_name使用了雙引號單引號混合的方式。
mysql> select user_name,(data->"$.location") from json_test where user_name = '"jianrong"';
| user_name | (data->"$.location") |
| "jianrong" | "gansu" |
1 row in set (0.00 sec)
如果帶有疑惑,我們只有單引號是否可以,答案會讓你失望。
mysql> select user_name,(data->"$.location") from json_test where user_name = 'jianrong';
empty set (0.00 sec)
所以不是嚴格意義上100%的相容性,至少在各式統一上我們還是需要一些額外的工作。
然後來看下執行計畫的情況,可以看到語句明顯使用到了索引,對於後期的資料分析和處理還是大有幫助的。
mysql> explain select user_name,(data->"$.location")from json_test where user_name = '"jeanron"';
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | extra |
| 1 | ****** | json_test | null | ref | idx_username | idx_username | 387 | const | 1 | 100.00 | null |
1 row in set, 1 warning (0.00 sec)
在這個基礎上如果做更多的分析,其實explain format=json也是一種改進方式,對於執行計畫,我們可以得到屬性值,通過解析的方式能夠把執行計畫做得更好。
json的新特性對於mysql來說確實是乙個不錯的特性,如果資料量巨大,還是需要考慮通過空間換時間的思路來改進。如果大家了解oracle,postgresql等資料庫,其實這些特性也是有的,oracle 12c裡面明確有這個特性,postgresql也有這個特性,還區分為json和jsonb,對於nosql來說,那更是它們擅長的,所以mysql實現這個是一種輔助,絕對不是做了顛覆性的改進。
歷史的車輪要前進,我們的方案只能是折中之後的方案。就好比早年的時候oracle全面支援xml,結果到現在這類需求明顯有些涼了。
json也不是萬金油,推薦大家參考這一篇。
獲取Json裡面的值
例如 我想獲取裡面code的值,也就是0000。兩種情況 1.知道json的名字 sr sr com.alibaba.fastjson.jsonobject jsonmap com.alibaba.fastjson.jsonobject.parseobject sr.tostring string ...
JSON學習四 JSON裡面的類
json的定義 一種輕量級的資料交換格式,具有良好的可讀和便於快速編寫的特性。業內主流技術為其提供了完整的解決方案 有點類似於正規表示式 獲得了當今大部分語言的支援 從而可以在不同平台間進行資料交換。json採用相容性很高的文字格式,同時也具備類似於c語言體系的行為。json.org 為什麼用jso...
JSON學習四 JSON裡面的類
json的定義 一種輕量級的資料交換格式,具有良好的可讀和便於快速編寫的特性。業內主流技術為其提供了完整的解決方案 有點類似於正規表示式 獲得了當今大部分語言的支援 從而可以在不同平台間進行資料交換。json採用相容性很高的文字格式,同時也具備類似於c語言體系的行為。json.org 為什麼用jso...