postgresql - 更快地从大型 jsonb 字段中检索多个值(postgresql 9.4)

标签 postgresql hstore jsonb

tl;dr

使用 PSQL 9.4,是否有一种方法可以从 jsonb 字段中检索多个值,例如您使用虚构的函数:

jsonb_extract_path(x, ARRAY['a_dictionary_key', 'a_second_dictionary_key', 'a_third_dictionary_key'])

希望加快选择多个值所需的几乎线性时间(1 个值 = 300 毫秒,2 个值 = 450 毫秒,3 个值 = 600 毫秒)

背景

我有以下 jsonb 表:

CREATE TABLE "public"."analysis" (
  "date" date NOT NULL,
  "name" character varying (10) NOT NULL,
  "country" character (3) NOT NULL,
  "x" jsonb,
  PRIMARY KEY(date,name)
);

大约有 100 000 行,其中每行都有一个 jsonb 字典,其中包含 90 多个键和相应的值。我正在尝试编写一个 SQL 查询来以相当快的方式(< 500 毫秒)选择几个(< 10)键+值

索引和查询:190ms

我首先添加了一个索引:

CREATE INDEX ON analysis USING GIN (x);

这使得基于“x”字典中的值的查询变得快速,例如:

SELECT date, name, country FROM analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100;

这需要大约 190 毫秒(我们可以接受)

检索字典值

但是,一旦我开始在 SELECT 部分中添加要返回的键,执行时间几乎呈线性上升:

1个值:300ms

select jsonb_extract_path(x, 'a_dictionary_key') from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100;

耗时 366 毫秒(+175 毫秒)

select x#>'{a_dictionary_key}' as gear_down_altitude from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100 ;

需要 300 毫秒(+110 毫秒)

3个值:600ms

select jsonb_extract_path(x, 'a_dictionary_key'), jsonb_extract_path(x, 'a_second_dictionary_key'), jsonb_extract_path(x, 'a_third_dictionary_key') from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100;

需要 600 毫秒(+410,或每个选定值 +100)

select x#>'{a_dictionary_key}' as a_dictionary_key, x#>'{a_second_dictionary_key}' as a_second_dictionary_key, x#>'{a_third_dictionary_key}' as a_third_dictionary_key from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100 ;

需要 600 毫秒(+410,或每个选定值 +100)

更快地检索更多值

有没有一种方法可以从一个 jsonb 字段中检索多个值,就像您使用虚函数那样:

jsonb_extract_path(x, ARRAY['a_dictionary_key', 'a_second_dictionary_key', 'a_third_dictionary_key'])

这可能会加速这些查找。它可以将它们作为列或作为列表/数组甚至 json 对象返回。

使用 PL/Python 检索数组

为了解决这个问题,我使用 PL/Python 制作了一个自定义函数,但这要慢得多(5 秒以上),可能是由于 json.loads:

CREATE OR REPLACE FUNCTION retrieve_objects(data jsonb, k VARCHAR[])
RETURNS TEXT[] AS $$
  if not data:
    return []

  import simplejson as json
  j = json.loads(data) 

  l = []
  for i in k:
    l.append(j[i])

  return l

$$ LANGUAGE plpython2u;

# Usage:
# select retrieve_objects(x, ARRAY['a_dictionary_key', 'a_second_dictionary_key', 'a_third_dictionary_key']) from analysis  where date > '2014-01-01' and date < '2014-05-01' 

更新 2015-05-21

我使用带有 GIN 索引的 hstore 重新实现了该表,性能几乎与使用 jsonb 相同,即对我的情况没有帮助。

最佳答案

您正在使用 #> operator ,看起来它执行路径搜索。您是否尝试过正常的 -> 查找?喜欢:

select  json_column->'json_field1'
,       json_column->'json_field2'

如果您使用临时表,看看会发生什么会很有趣。喜欢:

create temporary table tmp_doclist (doc jsonb)
;
insert  tmp_doclist
        (doc)
select  x
from    analysis
where   ... your conditions here ...
;
select  doc->'col1'
,       doc->'col2'
,       doc->'col3'
from    tmp_doclist
;

关于postgresql - 更快地从大型 jsonb 字段中检索多个值(postgresql 9.4),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30327140/

相关文章:

sql - 将两列和两行聚合为一

java - 是始终打开一个连接更好,还是每次需要某事时都建立一个连接更好?

mysql - mysql、Nosql、Cassandra、Mongodb、postgresql 等不同的数据库解决方案有什么区别,你什么时候使用它们?

javascript - 在不同服务器上使用 PHP 脚本从数据库中检索数据

java - 将 map 转换为 HStore

sql - jsonb 内部字段上的 Postgres GROUP BY

django - JSONB PostgreSQL 类型 : how to lookup

python - 如何在 Pyramid 中使用 SQLAlchemy HSTORE?

django - 在 Django 中实现 PostgreSQL HStore

java - PostgreSQL 的 JPA 查询