Индексирование массива jsonb в Postgres - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь настроить индекс GIN, но не думаю, что мой индекс используется при выполнении запроса, использую ли я оператор или функцию.

Среда

В нашемУ таблицы есть поле JSONB (json_aip), содержащее Json, которое выглядит следующим образом:

{
    "properties": {
        "pdi": {
            "contextInformation": {
                "tags": ["SOME_TAG"]
            },
    },
}

Создание таблицы:

create table t_aip (
    json_aip jsonb,
    [...]
);

CREATE INDEX idx_aip_tags 
ON t_aip 
USING gin ((json_aip -> 'properties' -> 'pdi' -> 'contextInformation' -> 'tags'));

Запрос оператора

Мы можемне используйте оператор ?|, как мы используем JDBC.Но, по слухам, я должен увидеть свой индекс при выполнении запроса такого типа.

EXPLAIN ANALYZE SELECT count(*)  
FROM storage.t_aip 
WHERE json_aip#>'{properties,pdi,contextInformation,tags}' ?| array['SOME_TAG']

Результат:

  Aggregate

  (cost=27052.16..27052.17 rows=1 width=8) (actual time=488.085..488.087 rows=1 loops=1)
  ->  Seq Scan on t_aip  (cost=0.00..27052.06 rows=42 width=0) (actual time=0.134..456.978 rows=16502 loops=1)
        Filter: ((json_aip #> '{properties,pdi,contextInformation,tags}'::text[]) ?| '{SOME_TAG}'::text[])
        Rows Removed by Filter: 17511
Planning time: 23.202 ms
Execution

time: 488.449 ms

Функциональный запрос

EXPLAIN ANALYZE SELECT count(*)  
FROM storage.t_aip 
WHERE jsonb_exists_any(
    json_aip#>'{properties,pdi,contextInformation,tags}', 
    array['SOME_TAG']
)

Результат:

QUERY PLAN
Aggregate  (cost=27087.00..27087.01 rows=1 width=8) (actual time=369.931..369.933 rows=1 loops=1)
  ->  Seq Scan on t_aip  (cost=0.00..27052.06 rows=13979 width=0) (actual time=0.173..350.437 rows=16502 loops=1)
        Filter: jsonb_exists_any((json_aip #> '{properties,pdi,contextInformation,tags}'::text[]), '{SOME_TAG}'::text[])
        Rows Removed by Filter: 17511
Planning time: 56.021 ms
Execution time: 370.252 ms

В индексе вообще ничего нет.Любая помощь приветствуется !

Я думаю, что мой индекс неверен, потому что он считает, что в конце пути json_aip -> 'properties' -> 'pdi' -> 'contextInformation' -> 'tags' он индексирует строку, является ли это массивом.Это мое мнение.

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

EDITED:

Я думал об обратном, но на самом деле ЕСТЬ разница между операторами (?|) и функциями (jsonb_exists_any) в отношении использования индекса в качестве индексаникогда не используется, когда запрос использует функции (jsonb).

Подробнее об этом можно прочитать здесь: https://dba.stackexchange.com/a/91007

Это был другой вопрос этой темы.

0 голосов
/ 22 октября 2018

Существует общее правило, согласно которому вы должны использовать одно и то же выражение как в индексе, так и в запросе, чтобы использовать индекс.С этим индексом:

CREATE INDEX idx_aip_tags 
ON t_aip 
USING gin ((json_aip#>'{properties,pdi,contextInformation,tags}'));

запрос будет использовать индекс

EXPLAIN ANALYZE 
SELECT count(*)  
FROM t_aip 
WHERE json_aip#>'{properties,pdi,contextInformation,tags}' ?| array['SOME_TAG']

                                                           QUERY PLAN                                                            
---------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=149.97..149.98 rows=1 width=0) (actual time=27.783..27.783 rows=1 loops=1)
   ->  Bitmap Heap Scan on t_aip  (cost=20.31..149.87 rows=40 width=0) (actual time=1.504..25.726 rows=20000 loops=1)
         Recheck Cond: ((json_aip #> '{properties,pdi,contextInformation,tags}'::text[]) ?| '{SOME_TAG}'::text[])
         Heap Blocks: exact=345
         ->  Bitmap Index Scan on idx_aip_tags  (cost=0.00..20.30 rows=40 width=0) (actual time=1.455..1.455 rows=20000 loops=1)
               Index Cond: ((json_aip #> '{properties,pdi,contextInformation,tags}'::text[]) ?| '{SOME_TAG}'::text[])

Обратите внимание, что индекс GIN поддерживает также оператор @>:

SELECT count(*)  
FROM t_aip 
WHERE json_aip#>'{properties,pdi,contextInformation,tags}' @> '["SOME_TAG"]'

, нобудьте осторожны при поиске более одного тега:

SELECT count(*)  
FROM t_aip 
-- this gives objects containing both tags:
-- WHERE json_aip#>'{properties,pdi,contextInformation,tags}' @> '["SOME_TAG", "ANOTHER_TAG"]'
-- and this gives objects with any of two tags:
WHERE json_aip#>'{properties,pdi,contextInformation,tags}' @> ANY(ARRAY['["SOME_TAG"]', '["ANOTHER_TAG"]']::jsonb[])
...