从 JSONB 字段中选择缓慢

Zek*_*erg 2 postgresql jsonb

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

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

我从不使用引用 JSONB 内部内容的 where 子句,只是选择 *. 即便如此,我还是尝试添加 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
Run Code Online (Sandbox Code Playgroud)

Pav*_*ule 5

Jsonb 是 PostgreSQL varlena 数据类型 - 这意味着当值大于 2KB 时,则将其存储在辅助表(名为 TOAST 表)中。指向 TOAST 表的指针存储在主表中。因此,当您不触摸 Jsonb 列时,则不会读取此值。

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

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

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