从 JSONB 字段中选择缓慢

Selecting from JSONB field slow

我有一个相对较小的 table(~50k 行)。当我 select 所有记录时,需要大约 40 秒。 table 有 3 个 JSONB 列。当我 select 除了 JSONB 之外的每一列时,查询需要大约 700 毫秒。

如果我只添加一个 JSONB 字段,查询时间会跳到将近 10 秒。

我从不使用 where 子句引用 JSONB 中的内容,只是 selecting *。即便如此,我还是尝试添加 GIN 索引,因为我看到它们经常被提及为 JSONB 的性能助推器。

我已经 运行 完全真空了。

Postgres 版本 9.6

 explain (analyze, buffers) select * from message;
   Seq Scan on message  (cost=0.00..5541.69 rows=52969 width=834) (actual 
   time=1.736..116.183 rows=52969 loops=1)
     Buffers: shared hit=64 read=4948
   Planning time: 0.151 ms
   Execution time: 133.555 ms

Jsonb 是 PostgreSQL varlena 数据类型 - 这意味着当值超过 2KB 时,它存储在辅助 table(名为 TOAST table)中。指向 TOAST table 的指针存储在 main table 中。所以当你不触摸 Jsonb 列时,则不会读取此值。

GIN 索引在这种情况下没有帮助。它仅有助于搜索。

50K 值上的 10 秒是很长的时间 - 也许您的 Jsonb 值很长,或者您的 IO 系统性能不佳。请检查 table 的大小,并检查 IO 的性能。廉价的云机器通常具有糟糕的 IO。

速度变慢的另一个可能原因是 Jsonb 数据类型的复杂性。 Jsonb 是 json 个子对象的序列化树。如果你不需要 Jsonb 数据类型的一些特殊特性,那么使用 JSON 数据类型。这只是测试(JSON 格式仅在输入时检查)。 JSONB 的输出比 Jsonb 快,因为 JSON 内部是文本,不需要任何操作。 Jsonb的输出应该是序列化的,什么比较贵。