在 Postgres 中索引一个 jsonb 数组
Indexing a jsonb array in Postgres
我尝试设置一个 GIN 索引,但我不认为当我 运行 请求时使用我的索引,无论我使用运算符还是函数。
环境
在我们的 table 中,我们有一个 JSONB 字段 (json_aip
) 包含一个 Json,看起来像这样:
{
"properties": {
"pdi": {
"contextInformation": {
"tags": ["SOME_TAG"]
},
},
}
Table 创作:
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'
它索引了一个 String 是否是一个数组。这是我的看法。
有一条通用规则,即您必须在索引和查询中使用完全相同的表达式才能使用索引。使用此索引:
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[])
已编辑:
我的想法恰恰相反,但实际上 运算符 (?|
) 和函数 (jsonb_exists_any
) 在索引使用方面存在 差异,如当查询使用 (jsonb) 函数时,从不使用索引。
您可以在此处了解更多信息:https://dba.stackexchange.com/a/91007
这是本主题的另一个问题。
编辑 2:
您可以创建可以使用索引并在您的代码中用作函数的函数别名,如下所示:
-- Define functions that calls the postgres native operator, to overpass the JDBC issue related to question mark
CREATE OR REPLACE FUNCTION rs_jsonb_exists_all(jsonb, text[])
RETURNS bool AS
'SELECT ?& ' LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION rs_jsonb_exists(jsonb, text)
RETURNS bool AS
'SELECT ? ' LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION rs_jsonb_exists_any(jsonb, text[])
RETURNS bool AS
'SELECT ?| ' LANGUAGE sql IMMUTABLE;
我尝试设置一个 GIN 索引,但我不认为当我 运行 请求时使用我的索引,无论我使用运算符还是函数。
环境
在我们的 table 中,我们有一个 JSONB 字段 (json_aip
) 包含一个 Json,看起来像这样:
{
"properties": {
"pdi": {
"contextInformation": {
"tags": ["SOME_TAG"]
},
},
}
Table 创作:
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'
它索引了一个 String 是否是一个数组。这是我的看法。
有一条通用规则,即您必须在索引和查询中使用完全相同的表达式才能使用索引。使用此索引:
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[])
已编辑:
我的想法恰恰相反,但实际上 运算符 (?|
) 和函数 (jsonb_exists_any
) 在索引使用方面存在 差异,如当查询使用 (jsonb) 函数时,从不使用索引。
您可以在此处了解更多信息:https://dba.stackexchange.com/a/91007
这是本主题的另一个问题。
编辑 2:
您可以创建可以使用索引并在您的代码中用作函数的函数别名,如下所示:
-- Define functions that calls the postgres native operator, to overpass the JDBC issue related to question mark
CREATE OR REPLACE FUNCTION rs_jsonb_exists_all(jsonb, text[])
RETURNS bool AS
'SELECT ?& ' LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION rs_jsonb_exists(jsonb, text)
RETURNS bool AS
'SELECT ? ' LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION rs_jsonb_exists_any(jsonb, text[])
RETURNS bool AS
'SELECT ?| ' LANGUAGE sql IMMUTABLE;