PostgreSql jsonb 列上的 GIN 索引未在查询中使用
Posted
技术标签:
【中文标题】PostgreSql jsonb 列上的 GIN 索引未在查询中使用【英文标题】:GIN index on PostgreSql jsonb column not being used in queries 【发布时间】:2019-05-23 15:18:30 【问题描述】:我正在使用 PostgreSql 9.6。 (请不要让我升级 - 我必须使用 9.6)
我有一个包含 jsonb 列的表。我在该列上创建了 GIN 索引。该表有 320,000 条记录。 “解释分析”表明该索引没有被使用,一个简单的查询大约需要 3 秒。
我们有一个调试记录器,它可以记录任何内容,但将其存储为 JSON,格式为 "key1":"value1", "key2":"value2", ...
我们通过提取键的值来收集统计信息。
表和索引是这样创建的:
CREATE TABLE log (
id SERIAL PRIMARY KEY,
logEntry jsonb
);
CREATE INDEX log_idx_logentry on log using gin (logentry);
我运行了一个我知道不会返回任何结果的查询:
SELECT id FROM log WHERE logentry->>'modality' = 'XT'
这需要 3 秒才能运行。
EXPLAIN ANALYSE SELECT id FROM log WHERE logentry->>'modality' = 'XT' produces:
Seq Scan on log (cost=0.00..32458.90 rows=1618 width=4) (actual time=1328.654..1328.660 rows=0 loops=1)
Filter: ((logentry ->> 'modality'::text) = 'XT'::text)
Rows Removed by Filter: 323527
Planning time: 0.450 ms
Execution time: 1328.724 ms
(5 rows)
如果我将查询写成类似的结果:
EXPLAIN ANALYSE SELECT id FROM log WHERE logentry->'modality' @> '"XT"'::jsonb
Seq Scan on log (cost=0.00..32458.90 rows=324 width=4) (actual time=1421.262..1421.266 rows=0 loops=1)
Filter: ((logentry -> 'modality'::text) @> '"XT"'::jsonb)
Rows Removed by Filter: 323527
Planning time: 0.080 ms
Execution time: 1421.309 ms
(5 rows)
而且,只是为了证明表中有东西,
SELECT COUNT(id) FROM log WHERE logentry->'modality' @> '"CT"'::jsonb
返回 42528
那么为什么不使用索引?在生产中,我们希望日志表包含数百万条记录。
【问题讨论】:
gin 索引不支持->
和->>
运算符。您可以尝试例如where logentry @> '"modality": "CT"'
这很简单。我确定我在搜索的某处看到了我使用的语法。那好吧。现在它正在使用位图堆扫描,“XT”查询的结果现在在 1.7 秒而不是 3 秒内返回。差别不大。
【参考方案1】:
klin 有正确答案。随着数据库越来越大,性能上的差异也越来越明显。
【讨论】:
以上是关于PostgreSql jsonb 列上的 GIN 索引未在查询中使用的主要内容,如果未能解决你的问题,请参考以下文章
带有 CriteriaQuery 的 JSONB 列上的“LIKE”表达式