PostgreSQL 未对 JSONB 上的 GIN 索引使用索引扫描

Posted

技术标签:

【中文标题】PostgreSQL 未对 JSONB 上的 GIN 索引使用索引扫描【英文标题】:PostgreSQL not using index scan over GIN index on JSONB 【发布时间】:2018-01-25 11:47:00 【问题描述】:

我在 PostgreSQL 中有一张表,其中包含一个 JSONB 列。 JSON 看起来像这样-'key':some_key, 'value': some_value. 我使用 -

在 JSON 中索引了 key
CREATE INDEX t3_index ON t3 USING GIN ((data->'key'));

表格的schama看起来像-

                Table "public.t3"
 Column | Type  | Collation | Nullable | Default 
--------+-------+-----------+----------+---------
 data   | jsonb |           |          | 
Indexes:
    "t3_index" gin ((data -> 'key'::text))

当我使用key 查询时,PostgreSQL 正在执行顺序扫描。

psql_eth=> explain (analyze, buffers) select * from t3 where data->>'key'='ZGJVcGdyYWRlXzIwMTcwNzE0ZGVkdXBsaWNhdGVEYXRh';
                                             QUERY PLAN                                             
----------------------------------------------------------------------------------------------------
 Seq Scan on t3  (cost=0.00..4201.65 rows=377 width=289) (actual time=0.017..42.976 rows=1 loops=1)
   Filter: ((data ->> 'key'::text) = 'ZGJVcGdyYWRlXzIwMTcwNzE0ZGVkdXBsaWNhdGVEYXRh'::text)
   Rows Removed by Filter: 75049
   Buffers: shared hit=3142
 Planning time: 0.068 ms
 Execution time: 42.996 ms
(6 rows)
    PostgreSQL 为什么要进行 seq 扫描? 如何让查询结果更快?如何让它使用 GIN 索引?

【问题讨论】:

edit您的问题并添加使用explain (analyze, buffers)(不仅仅是explain)生成的执行计划 优化器假设表只有 334 行,所以 seq 扫描是自然的选择。您的统计数据似乎不是最新的。运行analyze t4后计划会改变吗? 不,唯一可见的区别是 rows=351 (同时更改的总行数只有几 1000 秒)。 select count(*) from t4 给出 712313 为什么/如何假设 334 行? Execution time: 42.996 ms 您想要更快吗?顺便说一句,你的桌子叫什么名字? t3 t4. 【参考方案1】:

来自the documentation:

jsonb 的默认 GIN 运算符类支持使用***键存在运算符 ?、?& 和 ?| 的查询运算符和路径/值存在运算符@>.

索引不适用于等式运算符 (=)。您可以改用简单的 btree 索引:

create index on t3 ((data->>'key'));

【讨论】:

以上是关于PostgreSQL 未对 JSONB 上的 GIN 索引使用索引扫描的主要内容,如果未能解决你的问题,请参考以下文章

jsonb键/值上的模式匹配

jsonb内部字段上的Postgres GROUP BY

PostgreSQL 中 JSONB[] (JSONB ARRAY) 数据类型有啥用?

读取一个变量 JSONB 并将其放入 postgresql 的列中

postgresql jsonb 操作

Postgresql 9.4 - 转换为 JSONB 时输入语法无效