好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

介绍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,之后来看它们各占多少空间。
 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

=# 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数据花费稍微长一点时间,大小有没有区别呢?
 

?

1

2

3

4

5

6

=# 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版本开始,比如用操作符(注意 因为它返回文本,所以'->>'被采用;并且根据查询不同,索引采用不同的关键字)
 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

=# 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,仅支持@>,但是当搜索数据时性能表现不错,而且所占磁盘空间较小;

下面是它如何工作:
 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

=# 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中的jsonb数据类型的详细内容...

  阅读:57次