使用json列的Postgresql偏移行为

Mât*_*man 6 postgresql

使用postgresql 9.4我们有一个简单的联系人表(id文本不为null(作为pk),blob json)来试验移植couchdb crm数据库.我们最终将拆分为更多的列等,并为rdbms更自觉地处理数据,但这是暂时的.

大约有100k行.

我知道硬核postgresql性能专家建议不要使用偏移但是我可以接受一个小的性能惩罚(对100毫秒以下的任何东西都满意)

SELECT id FROM couchcontacts OFFSET 10000 LIMIT 10 
Run Code Online (Sandbox Code Playgroud)

如预期的那样需要<10ms

SELECT blob->>'firstName' FROM couchcontacts LIMIT 10 
Run Code Online (Sandbox Code Playgroud)

也需要<10ms(在这里假设blob列上有10个json解码操作)

SELECT blob->>'firstName' FROM couchcontacts OFFSET 10000 LIMIT 10 
Run Code Online (Sandbox Code Playgroud)

需要10秒钟!忽略偏移的低效率为什么这可能导致10,010个json解码操作?由于投影没有副作用,我不明白这不能快的原因?

这是json功能的限制对postgres来说相对较新吗?因此无法确定操作者->>不会产生副作用?

有趣的是将查询重写为10毫秒以下

SELECT jsonblob->>'firstName' FROM couchdbcontacts WHERE id IN (SELECT id FROM couchcontacts OFFSET 10000 LIMIT 10)
Run Code Online (Sandbox Code Playgroud)

有没有办法确保偏移不json解码偏移的记录?(即不执行选择投影)

"Limit  (cost=1680.31..1681.99 rows=10 width=32) (actual time=12634.674..12634.842 rows=10 loops=1)"
"  ->  Seq Scan on couchcontacts  (cost=0.00..17186.53 rows=102282 width=32) (actual time=0.088..12629.401 rows=10010 loops=1)"
"Planning time: 0.194 ms"
"Execution time: 12634.895 ms"
Run Code Online (Sandbox Code Playgroud)

Den*_*rdy 5

我跑了几个测试,我看到了类似的行为.这些中的每一个都在性能方面存在非重大差异:

  • select id ...
  • select indexed_field ...
  • select unindexed_field ...
  • select json_field ...
  • select * ...

但是,这个确实显示出性能上的差异:

  • select json_field->>'key' ...

当json_field为null时,性能影响可以忽略不计.如果它是空的,它会稍微降低一些东西.当它被填满时,它会明显降低.当字段加载更大的数据时,它会大幅降低.

换句话说,Postgres似乎想要为它访问的每一行重新序列化json数据.(这可能是一个错误,并且正在大量影响RoR开发人员看到他们如何使用json.)

Fwiw,我注意到重新安排查询以便它使用CTE将解决问题:

with data as (
  select * from table offset 10000 limit 10
)
select json_field->>'key' from data;
Run Code Online (Sandbox Code Playgroud)

(它可能会得到一个比id IN (...)你突出显示的查询更好的计划.)