table 上的 GIN INDEX,但 PostgreSQL EXPLAIN 显示了 Seq。扫描
GIN INDEX on the table, but PostgreSQL EXPLAIN shows me Seq. Scan
我有一个 table:
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, '{"technology": "PHP", "knowledge": 79 }'),
(3, '{"technology": "PHP", "knowledge": 97 }'),
(4, '{"technology": "MySQL", "knowledge": 85 }'),
(5, '{"technology": "MySQL", "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。扫描 ?
TLDR Gin 索引不适用于此类运算符。
查看 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)
经过进一步调整后,您可以改为使用直接针对这些 json 字段的普通索引:
CREATE INDEX idx_user_id_knowledge ON skill ((data->>'technology'), ((data->>'knowledge')::NUMERIC));
可用于查询中的两个条件。
我有一个 table:
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, '{"technology": "PHP", "knowledge": 79 }'),
(3, '{"technology": "PHP", "knowledge": 97 }'),
(4, '{"technology": "MySQL", "knowledge": 85 }'),
(5, '{"technology": "MySQL", "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。扫描 ?
TLDR Gin 索引不适用于此类运算符。
查看 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)
经过进一步调整后,您可以改为使用直接针对这些 json 字段的普通索引:
CREATE INDEX idx_user_id_knowledge ON skill ((data->>'technology'), ((data->>'knowledge')::NUMERIC));
可用于查询中的两个条件。