美文网首页
Postgre数据表不走索引排查

Postgre数据表不走索引排查

作者: 鸿雁长飞光不度 | 来源:发表于2022-12-08 19:39 被阅读0次

    案例:postgre数据库里面的transaction表采用了范围分区,按照月进行划分,同时有一个默认分区,存储当前月的数据。

    select * from transaction where id in ()
    

    上面根据这个主键id用in查询特别慢,当id的数量大于4时候就卡死了,小于4的时候非常快,in里面的id是否相同结果都一样。因为数据表是按照时间分区的,按照主键查询必定要跨越所有的分区查询数据,然后进行数据合并,但是每个分区内的数据主键是有索引的,所以理论上不会很慢才对。

    通过explian发现当id个数小于4的时候发现每个分区有两种执行计划,都走了索引所以总体还是比较快的。

    1. Bitmap Heap Scan:这种是走索引了,但是对每个id查询出的结果建立位图,最后按位图将结果合并。
    2. Index 就是走主键索引。

    但是当id超过4个,通过执行计划可以看到有2个分区执行计划变成了Seq Scan ,也就是顺序扫描,是这里导致查询缓慢的。


    这个不走索引大概是postgre觉得这种场景下走索引不划算,虽然id在每个分区是主键,但是分区表里面主键必须包含分区键字段,也就是分区表是id+created_at
    联合构成的,所以这里查询应该是和那种不分区的表只用id做主键的有区别,这里走的其实是一个联合索引。

    网上找了很久没有解决办法,同时奇怪的是只在sandbox环境有问题,线上却没有问题,sandbox数据量比线上要少一些。

    解决方案如下

    • 目前这些id业务中大部分都是处于default的分区的,所以先对这些id进行分组,然后手动的对每个分区表查询对应的id,这个最可控,也是最终采用的办法。

    • 尝试对id单独建立一个唯一索引,走这个单独的唯一索引肯定比之前的联合索引高,但是索引也是有代价的,数据本来就比较多了,单独建立一个这个不划算。

    • 执行这个查询前调用 SET enable_seqscan=true,这个禁止走串行扫描,可以解问题,但影响面太大。

    相关文章

      网友评论

          本文标题:Postgre数据表不走索引排查

          本文链接:https://www.haomeiwen.com/subject/lbbzxdtx.html