JSONPath 比较表达式中使用的索引 JSON 字段

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

鉴于 PostgreSQL 13.3 表和数据

CREATE TABLE transaction (message jsonb NOT NULL);
INSERT INTO transaction(message) VALUES ('{"amount": 1.00}'), ('{"amount": 2.00}');

索引

CREATE INDEX ON transaction (((message->'amount')::numeric));

用于查询

SELECT t.message FROM transaction t
WHERE (t.message->'amount')::numeric > 1.00;

两个索引都没有

CREATE INDEX ON transaction USING GIN (message);
CREATE INDEX ON transaction USING GIN (message jsonb_path_ops);

用于查询

SELECT t.message FROM transaction t
WHERE t.message @@ format('$.amount > %s', 1.00)::jsonpath;

PostgreSQL 中有没有办法对

transaction.message
列进行索引,以便 JSONPath
@@
运算符使用索引而不是进行 Seq Scan?

postgresql indexing jsonb jsonpath
1个回答
0
投票

我认为表中没有足够的行来使用索引。禁用会话的顺序扫描或尝试此操作

CREATE TABLE transaction (message jsonb NOT NULL);
INSERT INTO transaction(message) VALUES ('{"amount": 1.00}'), ('{"amount": 2.00}');
INSERT INTO transaction (message) SELECT ('{"amount": '|| random() * 100 || '}')::jsonb FROM generate_series(1, 1000);
CREATE INDEX ON transaction (((message->'amount')::numeric));

现在使用索引了

EXPLAIN ANALYZE SELECT t.message-> 'amount' FROM transaction t WHERE (t.message->'amount')::numeric = 1.00;

退货

Bitmap Heap Scan on transaction t  (cost=4.31..12.41 rows=5 width=32) (actual time=0.260..0.328 rows=1 loops=1)
  Recheck Cond: (((message -> 'amount'::text))::numeric = 1.00)
  Heap Blocks: exact=1
  ->  Bitmap Index Scan on transaction_numeric_idx  (cost=0.00..4.31 rows=5 width=0) (actual time=0.226..0.237 rows=1 loops=1)
        Index Cond: (((message -> 'amount'::text))::numeric = 1.00)
Planning Time: 0.131 ms
Execution Time: 0.448 ms

仍然选择顺序扫描

SELECT t.message-> 'amount' FROM transaction t WHERE (t.message->'amount')::numeric > 1.00

可能是因为规划者在统计数据中看到太多> 1.00 的值。

对于问题的第二部分

CREATE INDEX ON transaction USING GIN (message jsonb_path_ops);
EXPLAIN ANALYZE SELECT t.message FROM transaction t WHERE t.message @@ '$.amount == 1.00';

退货

Bitmap Heap Scan on transaction t  (cost=8.01..12.02 rows=1 width=36) (actual time=0.103..0.141 rows=1 loops=1)
  Recheck Cond: (message @@ '($.""amount"" == 1.00)'::jsonpath)"
  Heap Blocks: exact=1
  ->  Bitmap Index Scan on transaction_message_idx  (cost=0.00..8.01 rows=1 width=0) (actual time=0.051..0.061 rows=1 loops=1)
        Index Cond: (message @@ '($.""amount"" == 1.00)'::jsonpath)"
Planning Time: 0.120 ms
Execution Time: 0.227 ms

因此,只要有可能,就会使用这个索引,特别是在这种情况下,jsonpath 是

t.message @@ '$.amount == 1.00'

正如@Bergi 在下面的评论中指出的那样,问题的第二部分专门询问了

t.message @@ '$.amount > 1.00'
。我不能假装我确定知道,但我有一种感觉,索引只存储有关路径的信息,意味着明确存在的东西,并且对此类比较没有帮助。但这只是一个猜测。除了
==
之外,我没有看到它用于任何其他用途。

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