当前位置: 首页 > 编程笔记 >

介绍PostgreSQL中的jsonb数据类型

荣声
2023-03-14
本文向大家介绍介绍PostgreSQL中的jsonb数据类型,包括了介绍PostgreSQL中的jsonb数据类型的使用技巧和注意事项,需要的朋友参考一下

PostgreSQL 9.4 正在加载一项新功能叫jsonb,是一种新型资料,可以储存支援GIN索引的JSON 资料。换言之,此功能,在即将来临的更新中最重要的是,如果连这都不重要的话,那就把Postgres 置于文件为本数据库系统的推荐位置吧。

自从9.2开始,一个整合JSON 资料类型已经存在,带有一整套功能(例如资料产生和资料解构功能),还有9.3新增的操作者。当使用JSON 资料类型,资料的被存储成一完全一样的副本,功能还在此之上运作,还另外需要后台运作的重新分析。

这心得JSONB 资料类型以已降解的2元格式存储,所以,插入此资料会比JSON高效,因为后台不再需要重新分析,因此让它更快速运行,而且还兼顾GIN 索引。就是因为最后这个原因,我们实际上建议读者使用jsonb来代替json制作程式(当然你还可以因应需要而使用json)。请记住jsonb使用相同的操作者和功能,读者们可以看我之前的帖子去令你得到些什么启发(或者干脆看Postgres的文件)。
 

现在让我们看一下JSONB是如何工作的,同时和JSON比较一下。采用的测试数据是860万的geobase类型数据,大概1.1G大小,包括了城市名,国家代码(可以在这参见完整列表)等很多字段。首先通过底层复制(raw copy)来把这些数据存储到数据库的一个新表里面,之后把这张表通过一组填充因子是100的表转换成JSON/JSONB,之后来看它们各占多少空间。
 

=# COPY geodata FROM '$HOME/Downloads/allCountries.txt';
COPY 8647839
=# CREATE TABLE geodata_jsonb (data jsonb) with (fillfactor=100);
CREATE TABLE
=# CREATE TABLE geodata_json (data json) with (fillfactor=100);
CREATE TABLE
=# \timing
Timing is on.
=# INSERT INTO geodata_json SELECT row_to_json(geodata) FROM geodata;
INSERT 0 8647839
Time: 287158.457 ms
=# INSERT INTO geodata_jsonb SELECT row_to_json(geodata)::jsonb FROM geodata;
INSERT 0 8647839
Time: 425825.967 ms

生成JSONB数据花费稍微长一点时间,大小有没有区别呢?
 

=# SELECT pg_size_pretty(pg_relation_size('geodata_json'::regclass)) AS json,
     pg_size_pretty(pg_relation_size('geodata_jsonb'::regclass)) AS jsonb;
 json  | jsonb 
---------+---------
 3274 MB | 3816 MB
(1 row)

在JSON数据上面做索引从9.3版本开始,比如用操作符(注意 因为它返回文本,所以'->>'被采用;并且根据查询不同,索引采用不同的关键字)
 

=# CREATE INDEX geodata_index ON
  geodata_json ((data->>'country_code'), (data->>'asciiname'));
CREATE INDEX
=# SELECT pg_size_pretty(pg_relation_size('geodata_index'::regclass))
  AS json_index;
 json_index 
------------
 310 MB
(1 row)
=# SELECT (data->>'population')::int as population,
     data->'latitude' as latitude,
     data->'longitude' as longitude
  FROM geodata_json WHERE data->>'country_code' = 'JP' AND
    data->>'asciiname' = 'Tokyo' AND
    (data->>'population')::int != 0;
 population | latitude | longitude 
------------+----------+-----------
  8336599 | 35.6895 | 139.69171
(1 row)
=# -- Explain of previous query
                            QUERY PLAN                            
-------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on geodata_json (cost=6.78..865.24 rows=215 width=32)
  Recheck Cond: (((data ->> 'country_code'::text) = 'JP'::text) AND ((data ->> 'asciiname'::text) = 'Tokyo'::text))
  Filter: (((data ->> 'population'::text))::integer <> 0)
  -> Bitmap Index Scan on geodata_index (cost=0.00..6.72 rows=216 width=0)
     Index Cond: (((data ->> 'country_code'::text) = 'JP'::text) AND ((data ->> 'asciiname'::text) = 'Tokyo'::text))
 Planning time: 0.172 ms
(6 rows)

在这个例子里,计划(planner)可以使用bitmap索引扫描,同时使用了之前产生的索引。


现在,JSONB的一个新特点就是检查包含带有操作符@>的数据容量,这种数据是可以用GIN来索引的,这种操作符数据也包括了?,?|和?&(为了检查给定的关键字是否存在)。 GIN索引对两类操作符起作用:

    缺省操作符类,之前列出的四个;

    jsonb_hash_ops,仅支持@>,但是当搜索数据时性能表现不错,而且所占磁盘空间较小;

下面是它如何工作:
 

=# CREATE INDEX geodata_gin ON geodata_jsonb
   USING GIN (data jsonb_hash_ops);
CREATE INDEX
=# SELECT (data->>'population')::int as population,
   data->'latitude' as latitude,
   data->'longitude' as longitude
  FROM geodata_jsonb WHERE data @> '{"country_code": "JP", "asciiname": "Tokyo"}' AND
    (data->>'population')::int != 0;
 population | latitude | longitude 
------------+----------+-----------
  8336599 | 35.6895 | 139.69171
(1 row)
 =# SELECT pg_size_pretty(pg_relation_size('geodata_gin'::regclass)) AS jsonb_gin;
 jsonb_gin
-----------
 1519 MB
(1 row)
=# -- EXPLAIN of previous query
                   QUERY PLAN                   
-------------------------------------------------------------------------------------
 Bitmap Heap Scan on geodata_jsonb (cost=131.01..31317.76 rows=8605 width=418)
  Recheck Cond: (data @> '{"asciiname": "Tokyo", "country_code": "JP"}'::jsonb)
  Filter: (((data ->> 'population'::text))::integer <> 0)
  -> Bitmap Index Scan on geodata_gin (cost=0.00..128.86 rows=8648 width=0)
     Index Cond: (data @> '{"asciiname": "Tokyo", "country_code": "JP"}'::jsonb)
 Planning time: 0.134 ms

根据应用的需求,你或许想采用空间消耗低的索引,比如BTree建立在JSON数据上的索引类型;GIN索引有着更多的优点,因为它覆盖了所有的JSON字段,并且检查容量;

 类似资料:
  • 本文向大家介绍介绍PostgreSQL中的Lateral类型,包括了介绍PostgreSQL中的Lateral类型的使用技巧和注意事项,需要的朋友参考一下 PostgreSQL 9.3 用了一种新的联合类型! Lateral联合的推出比较低调,但它实现了之前需要使用编写程序才能获得的强大的新查询. 在本文中, 我将会介绍一个在 PostgreSQL 9.2 不可能被实现的渠道转换分析. 什么是 L

  • 本文向大家介绍请介绍下js的数据类型相关面试题,主要包含被问及请介绍下js的数据类型时的应答技巧和注意事项,需要的朋友参考一下 数字类型,包含整数和小数,以及 字符串 布尔值,和 方法类型,包含方法 、箭头函数 和生成器 对象类型,包含对象、数组和 空类型,但 被判定为,但其实际行为却和完全不同 未定义,包含以及未初始化以及未声明。 符号类型,ES6新引入的数据类型,通常用于创建唯一的键。 大整数

  • 本文向大家介绍Lua中的基本数据类型详细介绍,包括了Lua中的基本数据类型详细介绍的使用技巧和注意事项,需要的朋友参考一下 基础介绍 Lua是一种动态类型的语言。在语言中没有类型定义的语法,每个值都带有其自身的类型信息。在Lua中有8中基本类型,分别是: 1.nil(空)类型 2.boolean(布尔)类型 3.number(数字)类型 4.string(字符串)类型 5.userdata(自定义

  • 本文向大家介绍简单介绍Python中的几种数据类型,包括了简单介绍Python中的几种数据类型的使用技巧和注意事项,需要的朋友参考一下 大体上把Python中的数据类型分为如下几类: 由于Python中认为所有的东西都是对象,所以Python不用像其它一些高级语言那样主动声明一个变量的类型。 例如我要给一个变量i赋值100,python的实现 : C#的实现: 下面一一简单介绍这几种数据类型 数字

  • 我目前有一个表会话和一个列操作(JSONB)。 我能够使用正确地将数组从前端存储到数据库。 我的数组(数组值)的结构如下所示: 与我在SO上看到的许多关于修改JSONB或访问某些键的问题不同,我只对将整个JSONB数据转换回前端的数组感兴趣。 我的临时修复是通过数组进行映射,并使用Javascript中的json.parse()来重组数组中的每个对象。我不能对整个数组使用json.parse(),

  • 问题内容: 使用运算符将产生以下结果: 我希望能够实现以下结果(对于操作员来说只是一个占位符): 因此,您可以看到顶级键的子值已“合并”,使得结果包含和。 如何在Postgres中“深度”合并两个 JSONB 值? 如果可能的话,这可能吗? 一个更复杂的测试用例: 原始“合并”并成为对象的另一个测试用例: 问题答案: 您应该合并两个值都使用的未嵌套元素。在不平凡的查询中执行此操作可能会感到不舒服,