【问题标题】:PostgreSQL 10.4 - how to index jsonb for sql functions not operators?PostgreSQL 10.4 - 如何为 sql 函数而不是运算符索引 jsonb?
【发布时间】:2021-06-07 16:03:10
【问题描述】:

我有一个名为“k3_order”的表,其中包含 jsonb 列“json_delivery”。

该列的示例内容是:

{
    "delivery_cost": "11.99",
    "packageNumbers": [
        "0000000596034Q"
    ]
}

我已经在 json_delivery->'packageNumbers' 上创建了索引:

CREATE INDEX test_idx ON k3_order USING gin(json_delivery->'packageNumbers');

现在我使用这两个 SQL 查询:

SELECT id, delivery_method_id 
FROM k3_order 
WHERE jsonb_exists (json_delivery->'packageNumbers', '0000000596034Q');

SELECT id, delivery_method_id 
FROM k3_order 
WHERE json_delivery->'packageNumbers' ? '0000000596034Q';

第二个更快并且使用索引,但第一个没有。

有没有办法在 PostgreSQL 10.4 中创建索引以便查询 1) 使用它?

这在 PostgreSQL 10.4 或更新版本中是否可行?

EXPLAIN ANALYZE SELECT id, delivery_method_id 
FROM k3_order 
WHERE jsonb_exists (json_delivery->'packageNumbers', > '0000000596034Q');

产生:

Seq Scan on k3_order  (cost=0.00..117058.10 rows=216847 width=8 (actual time=162.001..569.863 rows=1 loops=1)
Filter: jsonb_exists((json_delivery -> 'packageNumbers'::text), '0000000596034Q'::text)
Rows Removed by Filter: 650539

Planning time: 0.748 ms
Execution time: 569.886 ms
EXPLAIN ANALYZE SELECT id, delivery_method_id 
FROM k3_order 
WHERE json_delivery->'packageNumbers' ? '0000000596034Q';

产生:

Bitmap Heap Scan on k3_order  (cost=21.04..2479.03 rows=651 width=8) (actual time=0.022..0.022 rows=1 loops=1)
Recheck Cond: ((json_delivery -> 'packageNumbers'::text) ? '0000000596034Q'::text)
Heap Blocks: exact=1
  ->  Bitmap Index Scan on test_idx  (cost=0.00..20.88 rows=651 width=0) (actual time=0.016..0.016 rows=1 loops=1)
        Index Cond: ((json_delivery -> 'packageNumbers'::text) ? '0000000596034Q'::text)

Planning time: 0.182 ms
Execution time: 0.050 ms

【问题讨论】:

  • 我刚查了,jsonb_exists没有支持功能。

标签: postgresql indexing jsonb


【解决方案1】:

索引只能在以下情况下被查询使用:

  • WHERE 条件包含<em>&lt;indexed expression&gt;</em> <em>&lt;operator&gt;</em> <em>&lt;constant&gt;</em> 形式的表达式,其中

    • 已在<em>&lt;indexed expression&gt;</em>上创建索引

    • <em>&lt;operator&gt;</em>是索引运算符类的索引族中的一个运算符

    • <em>&lt;constant&gt;</em> 是一个在索引扫描期间保持不变的表达式

  • ORDER BY子句与索引定义的顺序相同或完全相反,索引访问方式支持排序(从v13开始,如果索引包含ORDER BY的起始列,也可以使用索引子句)

  • PostgreSQL 版本为 v12 及更高版本,WHERE 条件包含bool_func(...) 形式的表达式,其中函数返回boolean 并具有planner support function

现在json_delivery-&gt;'packageNumbers' ? '0000000596034Q'满足第一个条件,所以可以使用索引扫描。

jsonb_exists(json_delivery-&gt;'packageNumbers', &gt; '0000000596034Q')只有在有jsonb_exists的planner支持功能的情况下才能使用索引,但没有:

SELECT prosupport FROM pg_proc
WHERE proname = 'jsonb_exists';

 prosupport 
════════════
 -
(1 row)

【讨论】:

  • 好吧 jsonb_exists 返回布尔值,它应该这样工作。以下是所有 PostgreSQL json 相关函数的列表:github.com/tztztztz/List-of-all-PostgreSQL-10-operators/blob/…
  • 是的,但是看我最后的查询,显示它没有支持功能。所以它不会工作。我们可能会欢迎一个补丁来添加支持功能。
  • 如果这种查询将使用索引,这将是我正在使用的 ORM 的理想选择:SELECT id, delivery_method_id FROM k3_order WHERE jsonb_exists(CAST(jsonb_object_field_text(json_delivery, 'packageNumbers') as jsonb), '0000000596034Q')
  • 如我所说,欢迎你写补丁。
  • 嗯,我刚刚在另一台测试机器上安装了 PostgreSQL 13,sql SELECT prosupport FROM pg_proc WHERE proname = 'jsonb_exists'; 显示它是支持的,但是另一个查询仍然没有使用索引。
猜你喜欢
  • 2021-07-22
  • 2017-09-11
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 2019-10-09
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多