Postgres:搜索jsonb数组字段很慢

问题描述 投票:0回答:2

我们正在为我们的一个项目更改DB(PostgreSQL 10.11)结构。更改之一是将uuid []类型的字段(称为“ areasoflawid”)移动到jsonb字段(称为“ data”)中。

所以,我们有一个看起来像这样的表:

CREATE TABLE public.documents
(
  id serial,
  areasoflawid uuid[], --the field to be moved into the ‘data’
  data jsonb,
  ….
)

我们不更改数组或其结构的值。也就是说,documents.data->'元数据'->'areaoflawids'包含与document.areasoflawid相同的项目)数据迁移后,存储在“数据”字段中的JSON具有以下结构:

{
   ...
   "metadata": {
      ...
      "areaoflawids": [
         "e34e0ee5-78e0-4d92-9186-ac69c109408b",
         "b3af9163-d910-4d19-8f40-0602b75c25b0",
         "50dc7fd8-ebdf-4cd2-bcab-b8d755fe96e8",
         "8955c062-363f-4a1a-ac3c-d1c2ffe96c9b",
         "bdb79f9f-4539-45f5-ac82-92baaf915f6c"
      ],
      ....
   },
   ...
}

因此,在迁移数据之后,我们开始对与jsonb字段相关的查询进行基准测试,并发现在数组字段文档中进行搜索。data->'metadata'->'areaoflawids'比在uuid []字段document.areasoflawid上花费的时间更长。

以下是查询:

--search over jsonb array field, takes 6.2 sec, returns 13615 rows
SELECT id FROM documents WHERE data->'metadata'->'areaoflawids' @> '"e34e0ee5-78e0-4d92-9186-ac69c109408b"'

--search over uuid[] field, takes 600ms, returns 13615 rows
SELECT id FROM documents WHERE areasoflawid @> ARRAY['e34e0ee5-78e0-4d92-9186-ac69c109408b']::uuid[]

这里是jsonb字段的索引:

CREATE INDEX test_documents_aols_gin_idx
  ON public.documents
  USING gin
  (((data -> 'metadata'::text) -> 'areaoflawids'::text) jsonb_path_ops);

这是执行计划:

EXPLAIN ANALYZE SELECT id FROM documents WHERE data->'metadata'->'areaoflawids' @> '"e34e0ee5-78e0-4d92-9186-ac69c109408b"'


"Bitmap Heap Scan on documents  (cost=6.31..390.78 rows=201 width=4) (actual time=2.297..5859.886 rows=13614 loops=1)"
"  Recheck Cond: (((data -> 'metadata'::text) -> 'areaoflawids'::text) @> '"e34e0ee5-78e0-4d92-9186-ac69c109408b"'::jsonb)"
"  Heap Blocks: exact=4859"
"  ->  Bitmap Index Scan on test_documents_aols_gin_idx  (cost=0.00..6.30 rows=201 width=0) (actual time=1.608..1.608 rows=13614 loops=1)"
"        Index Cond: (((data -> 'metadata'::text) -> 'areaoflawids'::text) @> '"e34e0ee5-78e0-4d92-9186-ac69c109408b"'::jsonb)"
"Planning time: 0.133 ms"
"Execution time: 5862.807 ms"

[通过jsonb字段进行的其他查询以可接受的速度工作,但是此特定搜索的速度比通过单独字段进行的搜索慢10倍。我们期望它会慢一些,但不会那么糟。我们考虑将“ areasoflawid”字段保留为单独字段的选项,但我们绝对希望将其移到json内。我一直在使用不同的索引和操作(也使用?和?|),但是搜索仍然很慢。任何帮助表示赞赏!

arrays postgresql indexing jsonb
2个回答
0
投票

在索引中查找13,614个候选匹配非常快(1.608毫秒)。最慢的部分是从表本身读取所有这些行。如果打开track_io_timing,然后执行EXPLAIN (ANALYZE, BUFFERS),我确定您会发现您正在等待IO。如果您连续运行几次查询,查询速度会更快吗?

我认为您在此处进行的基准测试不平等,其中一个表已在缓存中,而另一个表则不在。但是也可能是新表太大,无法实际容纳在缓存中。


0
投票

感谢您的回复!我们从该帖子中提出了另一个解决方案:https://www.postgresql.org/message-id/CAONrwUFOtnR909gs+7UOdQQB12+pXsGUYu5YHPtbQk5vaE9Gaw@mail.gmail.com。查询现在大约需要600-800毫秒才能执行。所以,这是解决方案:

CREATE OR REPLACE FUNCTION aol_uuids(data jsonb) RETURNS TEXT[] AS
$$
    SELECT 
        array_agg(value::TEXT) as val
    FROM 
        jsonb_array_elements(case jsonb_typeof(data) when 'array' then data else '[]' end)
$$ LANGUAGE SQL IMMUTABLE;


SELECT id FROM documents WHERE aol_uuids(data->'metadata'->'areaoflawids')@>ARRAY['"e34e0ee5-78e0-4d92-9186-ac69c109408b"']

© www.soinside.com 2019 - 2024. All rights reserved.