gpt4 book ai didi

postgresql - 为什么 Postgres 对 jsonb 列的查找如此缓慢?

转载 作者:行者123 更新时间:2023-11-29 11:29:58 24 4
gpt4 key购买 nike

我有一个表 targeting,其中有一列 marital_status 类型为 text[] 和另一列 data类型为 jsonb。这两列的内容是一样的,只是格式不同(只是为了演示)。示例数据:

 id |      marital_status      |                        data                       
----+--------------------------+---------------------------------------------------
1 | null | {}
2 | {widowed} | {"marital_status": ["widowed"]}
3 | {never_married,divorced} | {"marital_status": ["never_married", "divorced"]}
...

表中有69万多条记录,随机组合。

查找 text[] 列

EXPLAIN ANALYZE SELECT marital_status
FROM targeting
WHERE marital_status @> '{widowed}'::text[]

没有索引

通常需要 < 900 毫秒而不创建任何索引:

Seq Scan on targeting  (cost=0.00..172981.38 rows=159061 width=28) (actual time=0.017..840.084 rows=158877 loops=1)
Filter: (marital_status @> '{widowed}'::text[])
Rows Removed by Filter: 452033
Planning time: 0.150 ms
Execution time: 845.731 ms

带索引

使用索引通常需要 < 200 毫秒(改进 75%):

CREATE INDEX targeting_marital_status_idx ON targeting ("marital_status");

结果:

Index Only Scan using targeting_marital_status_idx on targeting  (cost=0.42..23931.35 rows=159061 width=28) (actual time=3.528..143.848 rows=158877 loops=1)"
Filter: (marital_status @> '{widowed}'::text[])
Rows Removed by Filter: 452033
Heap Fetches: 0
Planning time: 0.217 ms
Execution time: 148.506 ms

在 jsonb 列上查找

EXPLAIN ANALYZE SELECT data
FROM targeting
WHERE (data -> 'marital_status') @> '["widowed"]'::jsonb

没有索引

通常需要 < 5,700 毫秒而不创建任何索引(慢 6 倍以上!):

Seq Scan on targeting  (cost=0.00..174508.65 rows=611 width=403) (actual time=0.095..5399.112 rows=158877 loops=1)
Filter: ((data -> 'marital_status'::text) @> '["widowed"]'::jsonb)
Rows Removed by Filter: 452033
Planning time: 0.172 ms
Execution time: 5408.326 ms

带索引

使用索引通常需要 < 3,700 毫秒(改进 35%):

CREATE INDEX targeting_data_marital_status_idx ON targeting USING GIN ((data->'marital_status'));

结果:

Bitmap Heap Scan on targeting  (cost=144.73..2482.75 rows=611 width=403) (actual time=85.966..3694.834 rows=158877 loops=1)
Recheck Cond: ((data -> 'marital_status'::text) @> '["widowed"]'::jsonb)
Rows Removed by Index Recheck: 201080
Heap Blocks: exact=33723 lossy=53028
-> Bitmap Index Scan on targeting_data_marital_status_idx (cost=0.00..144.58 rows=611 width=0) (actual time=78.851..78.851 rows=158877 loops=1)"
Index Cond: ((data -> 'marital_status'::text) @> '["widowed"]'::jsonb)
Planning time: 0.257 ms
Execution time: 3703.492 ms

问题

  • 为什么 text[] 列的性能如此之高,即使不使用索引也是如此?
  • 为什么向 jsonb 列添加索引只会将性能提高 35%?
  • 是否有更高效的方法来查找 jsonb 列?

最佳答案

这似乎是个简单的问题。本质上你是在问为什么,

CREATE TABLE foo ( id int, key1 text );

CREATE TABLE bar ( id int, jsonb foo );

@Craig 在评论中回答了这个问题

GIN indexing is generally less efficient than a b-tree, so that much is expected.

该架构中的空值也应显示为

SELECT jsonb_build_object('marital_status',ARRAY[null]);
jsonb_build_object
----------------------------
{"marital_status": [null]}
(1 row)

而不是{}。 PostgreSQL 使用许多快捷方式来快速更新 jsonb 对象,并使索引空间高效。

如果这些都没有意义,请查看此伪表。

CREATE TABLE foo ( id int, x text, y text, z text )
CREATE INDEX ON foo(x);
CREATE INDEX ON foo(y);
CREATE INDEX ON foo(z);

这里我们在表上有三个 btree 索引。让我们看一个类似的表..

CREATE TABLE bar ( id int, junk jsonb );
CREATE INDEX ON bar USING gin (junk);
INSERT INTO bar (id,junk) VALUES (1,$${"x": 10, "y": 42}$$);

要使 barfoo 一样执行,我们需要两个 btree,它们都比我们拥有的单个 GIN 索引大。如果你这样做了

INSERT INTO bar (id,junk) VALUES (1,$${"x": 10, "y": 42, "z":3}$$);

我们必须在 z 上有另一个 btree 索引,这又将是巨大的。你可以看到我要去哪里。 jsonb 很棒,但索引和模式建模的复杂性与数据库不相称。您不能只将数据库缩减为 jsonb 列,发出 CREATE INDEX 并期望获得相同的性能。

关于postgresql - 为什么 Postgres 对 jsonb 列的查找如此缓慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41022627/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com