实战7:Postgresql JSON 数据类型大探险
1. 前言
这些年,Nosql
以及Newsql
都刮起过一番浪潮,而sql终究还是岿然不动,不仅没有被打垮,反而变得更加大。Postgresql
号称世界上最先进的关系数据库,很早的时候便已经开始支持文档性数据类型了,而且在9.3
以后的每一个版本,都提供了更多的新特性。
Postgresql 最重要的文档性数据类型就是JSON
了,与 MongoDB 的BSON
相比较,Postgresql 或许更加强大,因为它能与原有的关系性范式兼容,给数据库存储与维护带来了更多的可行性和便利性。
Postgresql 的JSON
类型功能十分强大,不仅支持基本的增删查改,属性判断,还支持索引和搜索;当然 MongoDB 也有无可替代的特性,不仅功能强大,而且天然分布式。如果你对文档数据存储的特性并没有太高的要求,且需要与原来的关系数据库兼容,那么 Postgresql 或许是你更好的选择。
2. JSON 数据类型
JSON 数据类型几乎已经是现在Web
开发的标配了,MysqL
在5.7
以后也提供了它的支持,不过即使到现在,MysqL 对于 JSON 的支持也有限,而 Postgresql 对 JSON 的支持十分强大。
Postgresql 在 9.3 版本对 JSON 做了显著功能增强外,在 9.4 引入了JSONB
类型,JSONB 类型是 JSON 类型的二进制版,不仅存储空间更小,性能更好,而且还支持索引,在 12 这个大版本中,直接引入了 JSON path 特性来方便的操作 JSON 数据,让 JSON 的操作更加方便和有效。
接下来,就让我们一起来学习 Postgresql 的 JSON 类型吧。
3. json 与 jsonb
我们来实操一下二者的使用吧。
3.1 使用 json
首先,我们看一下 json:
SELECT '{"username":"pedro","age":23}'::json;
json
-------------------------------
{"username":"pedro","age":23}
在 Postgresql 中::
符号用于类型转换,该语句将字符串'{"username":"pedro","age":23}'
,通过类型转换为json
,得到了 json 数据结果。
前面,我们谈到 json 以文本格式存储数据,且插入较快,那么是不是真的如此了?
SELECT '{"username":"pedro", "age": 23}'::json;
json
----------------------------------------
{"username":"pedro", "age": 23}
Time: 0.221 ms
3.2 使用 jsonb
从结果可以看出 json 确实以文本格式存储了数据,多余的空格依旧存在,那么再看 jsonb:
SELECT '{"username":"pedro", "age": 23}'::jsonb;
jsonb
----------------------------------
{"age": 23, "username": "pedro"}
Time: 0.265 ms
可以看到,jsonb 处理多余的空格,因此消耗的时候多了那么一点,在实际的测试中,json 的插入性能确实比 jsonb 要高。
4. JSON 类型增删查改
由于 json 和 jsonb 的操作几乎一致,但 jsonb 更为增大,支持更多的特性,因此我们以 jsonb 为例,来看一看它是如何进行增删查改的。
首先,我们新建测试表:
CREATE TABLE movie (
id serial PRIMARY KEY,
info jsonb
);
在 movie 表中,id 是自增的主键,而 info 字段是我们的主角,数据类型是jsonb。
4.1 增
由于 id 是 serial 类型,即自增,因此我们只需插入 info 数据即可:
INSERT INTO movie (info)
VALUES('{ "title": "我是路人甲", "rate": 7.4, "category": ["剧情","喜剧"]}'),
('{ "title": "铁拳","rate": 7.1, "category": ["剧情","动作","运动"]}');
4.2 查
4.2.1 json 路径操作符查询
SELECT info->'title' FROM movie;
?column?
--------------
"我是路人甲"
"铁拳"
SELECT info->>'title' FROM movie;
?column?
------------
我是路人甲
铁拳
->
与->>
二者是有区别的,->
返回的是 jsonb 类型,而->>
返回的是文本类型。
我们还可以通过下标来返回数组对象:
SELECT info->'category'-> from movie;
?column?
----------
"剧情"
"剧情"
4.2.2 json 路径数组查询
SELECT info#>array['category','1'] from movie;
?column?
----------
"喜剧"
"动作"
4.3 改
4.3.1 添加 json 字段
我们也可以通过 Update 指令,来添加 json 字段:
UPDATE movie SET info = info || '{"showtime": 2015.0}'::jsonb WHERE id = ;
id | info
----+----------------------------------------------------------------------------------------
1 | {"rate": 7.4, "title": "我是路人甲", "category": ["剧情", "喜剧"], "showtime": 2015.0}
4.3.2 删除 json 字段
通过-
我们可以删除 jsonb 中的某个字段:
UPDATE movie SET info = info - 'showtime'WHERE id = ;
id | info
----+--------------------------------------------------------------------
1 | {"rate": 7.4, "title": "我是路人甲", "category": ["剧情", "喜剧"]}
4.4 删
那么 Where 如何来过滤jsonb
字段里面的值了?
4.4.1 jsonb 匹配运算符
jsonb
支持多种匹配运算符,常见的有:
匹配运算符 | 作用 | 说明 |
---|---|---|
= | 等值比较 | 比较两个 json 是否相等 |
@> | 包含关系判定符 | 判断 json 中是有含有某些字段 |
<@ | 被包含关系判定符 | 判断 json 是否被另一个 json 包含 |
? | 键值存在判定符 | 判断 json 中是否存在某个键 |
4.4.2 使用匹配运算符
SELECT info->'rate' FROM movie WHERE info @> '{"title":"我是路人甲"}';
?column?
----------
7.4
因此,我们也可以使用这样的方式来删除:
DELETE FROM movie WHERE info @> '{"title":"我是路人甲"}';
注意: Postgresql 的 JSON 数据类型操作实则很复杂,需要大量的篇章来介绍,我们无法在一个实战小节来覆盖,如果你感兴趣,可以阅读官方文档,或者 PostgreSQL中文网。
5. jsonb 索引
前面我们说到,与 json 类型相比,jsonb 额外支持索引,这也是为什么推荐你使用 jsonb 的原因,因为数据量一旦大起来,没有索引
的查询会十分缓慢。
5.1 创建 jsonb 索引
jsonb 创建索引也十分简单,以上面的 movie 表为例:
CREATE INDEX movie_info_gin_index ON movie USING gin(info);
movie_info_gin_index
是索引名称,gin(info)
括号里面的 info 表示使用 movie 表中的 info 字段创建索引。
5.2 索引操作
jsonb 上的 gin 索引操作有一定的限制,它支持以下几个操作符:
5.3 使用索引
例如以下查询将会使用索引:
查询包含 title 为 铁拳的记录。
SELECT info FROM movie WHERE info @> '{"title":"铁拳"}';
查询包含 title 的记录。
SELECT info FROM movie WHERE info ? 'title';
查询包含 title 或 category 的记录。
SELECT info FROM movie WHERE info ?| array['title','category'];
5.4 额外索引
但是如果你使用->>
操作符,则不会走索引。
SELECT info FROM movie WHERE info->>'title' = '铁拳';
若要支持->>
索引,你必须为它也建立单独的索引,如下:
CREATE INDEX movie_info_title_index ON movie USING btree((info ->> 'title'));
6. 小结
关于 Postgresql JSON 的介绍到这里也将告一段落了,我们总结一下: