背景
1、产品的问题点
2、问题点背后涉及的技术原理
- PG 的索引没有TUPLE版本信息, 所以必须回表才能判断记录是否是dead tuple, 是否对当前事务可见.
- 为了解决这个问题, PG引入VM file, 记录每个data block的状态, 当datablock为clean状态时, 则不需要回表, 但是也要访问VM才能判断datablock为clean状态呀, 所以离散IO次数是没有节省下来的, 节省的是IO覆盖范围, 毕竟VM里面2bit就表示1个data block(默认8KB).
3、这个问题将影响哪些行业以及业务场景
- 对IO敏感的场景
- 多对象的时序、时空场景, 对某个对象, 范围扫描大量记录, 需要回表, 产生大量离散IO. 例如查询某个车辆的轨迹.
4、会导致什么问题?
- 即使采用 include index , 叶子节点包含需要查询的所有数据, 但是如果需要回表判断, 离散IO依旧是问题(从索引到table或VM文件都是离散IO).
- 额外对table数据文件的回访, 导致浪费shared buffer.
- 在删除大量数据后 或者 更新大量数据后, 如果索引的垃圾版本未及时进行垃圾回收, 将导致命中这部分索引的Query性能急剧下降.
5、业务上应该如何避免这个坑
- 尽量不要使用更新, 使得大部分数据块内的记录都是对所有会话可见, 所以不需要回表查询, 减少IO.
- 按对象ID分区, 使用BRIN索引代替BTREE索引, 减少时序类数据的范围搜索IO.
6、业务上避免这个坑牺牲了什么, 会引入什么新的问题
7、数据库未来产品迭代如何修复这个坑