You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让PostgreSQL GIN索引与jsonb_*函数配合生效?

问题:使用jsonb_*函数时PostgreSQL无法利用GIN索引

我发现当在查询中使用jsonb_*函数时,PostgreSQL无法使用GIN索引,这个问题在jsonb_ops和jsonb_path_ops操作类中都存在。


准备工作

1. 创建表及GIN索引

CREATE TABLE applications
(
    id          TEXT PRIMARY KEY,
    application JSONB
);
CREATE INDEX ON applications USING gin (application jsonb_path_ops);

2. 插入大量测试数据

为了让PostgreSQL更倾向于使用索引,插入10万条测试数据:

INSERT INTO applications(id, application)
VALUES ('1', '{
  "type_code": 1,
  "persons": [
    {
      "type_code": 4,
      "firstname": "John",
      "lastname": "Doe"
    }
  ]
}');
INSERT INTO applications (SELECT i, a.application FROM applications a, generate_series(2, 100000) i);

测试查询对比

1. 使用@?操作符(索引生效)

执行以下查询:

EXPLAIN ANALYZE
SELECT * FROM applications
WHERE applications.application @? '$.persons[*] ? (@.type_code == 3)';

执行计划显示GIN索引被成功使用:

-- Bitmap Heap Scan on applications  (cost=64.00..68.01 rows=1 width=130) (actual time=0.410..0.419 rows=0 loops=1)
-- "  Recheck Cond: (application @? '$.\"\"persons\"\"[*]?(@.\"\"type_code\"\" == 3)'::jsonpath)"
--   ->  Bitmap Index Scan on applications_application_idx  (cost=0.00..64.00 rows=1 width=0) (actual time=0.095..0.096 rows=0 loops=1)
-- "        Index Cond: (application @? '$.\"\"persons\"\"[*]?(@.\"\"type_code\"\" == 3)'::jsonpath)"
-- Planning Time: 1.493 ms
-- Execution Time: 0.861 ms

2. 使用jsonb_path_exists函数(索引未生效)

执行以下查询:

EXPLAIN ANALYZE
SELECT * FROM applications
WHERE jsonb_path_exists(
      applications.application,
      '$.persons[*] ? (@.type_code == 3)'
);

执行计划显示采用全表扫描,未使用GIN索引:

-- Aggregate  (cost=3374.33..3374.34 rows=1 width=8) (actual time=114.048..114.055 rows=1 loops=1)
--   ->  Seq Scan on applications  (cost=0.00..3291.00 rows=33333 width=0) (actual time=0.388..109.580 rows=100000 loops=1)
-- "        Filter: jsonb_path_exists(application, '$.\"\"persons\"\"[*]?(@.\"\"type_code\"\" == 3)'::jsonpath, '{}'::jsonb, false)"
-- Planning Time: 1.514 ms
-- Execution Time: 114.674 ms

疑问与需求

能否让第二个使用jsonb_path_exists函数的查询也用上GIN索引?我更倾向于使用jsonb_*函数,因为可以通过位置参数构建动态查询,比如:

SELECT * FROM applications
WHERE jsonb_path_exists(
      applications.application,
      '$.persons[*] ? (@.type_code == $person_type_code)',
      jsonb_build_object('person_type_code', $1)
);

内容的提问来源于stack exchange,提问作者donmaro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:13:18