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

y4ekin9u  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(1)|浏览(104)

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?

kmb7vmvb

kmb7vmvb1#

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

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'。我不能假装我知道肯定,但我有一种感觉,索引只存储有关路径的信息,这意味着明确存在的东西,并且对这种比较没有帮助。但这只是一个猜测。我没有看到它用于==以外的任何东西。

相关问题