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 索引未在查询中使用的主要内容,如果未能解决你的问题,请参考以下文章

用于比较 JSONB 值的 PostgreSQL 索引

pgsql jsonb的索引

带有 CriteriaQuery 的 JSONB 列上的“LIKE”表达式

如何在 jsonb 列上使用 Spring JPA 进行查询?

如何使用PostgreSQL中的JSONB数据类型

检查PostgreSQL jsonb列是不是包含某些字符串的快速方法