表上有 GIN INDEX,但 PostgreSQL EXPLAIN 显示了 Seq扫描

问题描述

我有一张桌子:

CREATE TABLE skill (
    user_id integer NOT NULL,data jsonb
);

和 jsonb 列上的 gin 索引:

CREATE INDEX idx_user_id_kNowledge ON skill USING gin (data);

INSERT INTO skill(user_id,data)
VALUES (1,'{"technology": "PHP","kNowledge": 77 }'),(2,"kNowledge": 79 }'),(3,"kNowledge": 97 }'),(4,'{"technology": "MysqL","kNowledge": 85 }'),(5,"kNowledge": 89 }');

但是当我运行 EXPLAIN 查询时:

EXPLAIN
SELECT * FROM skill
WHERE data->>'technology' = 'PHP' AND (data->>'kNowledge')::NUMERIC > 50;

输出如下:

Seq Scan on skill (cost=0.00..41.75 rows=2 width=36)
Filter: (((data ->> 'technology'::text) = 'PHP'::text) AND (((data ->> 'kNowledge'::text))::numeric > '50'::numeric))

为什么查询规划器不使用我创建的 gin 索引而不是 Seq。扫描?

http://sqlfiddle.com/#!17/35f2c/5

解决方法

TLDRGin 索引不适用于此类运算符。


查看 operators for GIN indexes,您可以看到 jsonb 类型唯一支持的运算符是:? ?& ?| @> @? @@

有关这些含义的信息,请参阅 JSON Function and Operators 文档。根据您的查询,如果您这样重写查询,它只能优化文本比较:

SELECT * FROM skill
WHERE data @> '{"technology": "PHP"}' AND (data->>'knowledge')::NUMERIC > 50;

产生以下查询计划:

Bitmap Heap Scan on skill (cost=16.01..20.03 rows=1 width=32)
Recheck Cond: (data @> '{"technology": "PHP"}'::jsonb)
  Filter: (((data ->> 'knowledge'::text))::numeric > '50'::numeric)
  -> Bitmap Index Scan on idx_user_id_knowledge (cost=0.00..16.01 rows=1 width=0)
     Index Cond: (data @> '{"technology": "PHP"}'::jsonb)

SQLFiddle to play around in


经过一些进一步的摆弄,您可以改为使用直接针对这些 json 字段的普通索引:

CREATE INDEX idx_user_id_knowledge ON skill  ((data->>'technology'),((data->>'knowledge')::NUMERIC));

可用于查询中的两个条件。

Updated fiddle

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...