【问题标题】:postgres seq scan on two partitionspostgres seq 扫描两个分区
【发布时间】:2021-06-25 13:58:17
【问题描述】:

在 rp_fk 列上直接查询 ch 表时,几乎所有分区都使用索引。

explain analyze select * from oc.ch ch  where rp_fk = 'abc123';

Append  (cost=0.14..9469.61 rows=2357 width=10008) (actual time=0.164..0.166 rows=0 loops=1)
  ->  Index Scan using ch_2016_rp_fk_idx1 on ch_2016 ch  (cost=0.14..8.16 rows=1 width=11097) (actual time=0.015..0.016 rows=0 loops=1)
        Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Index Scan using ch_2017_rp_fk_idx1 on ch_2017 ch_1  (cost=0.14..8.16 rows=1 width=10477) (actual time=0.022..0.022 rows=0 loops=1)
        Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Index Scan using ch_2018_rp_fk_idx1 on ch_2018 ch_2  (cost=0.56..4.58 rows=1 width=12295) (actual time=0.031..0.031 rows=0 loops=1)
        Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Index Scan using ch_2019_rp_fk_idx1 on ch_2019 ch_3  (cost=0.69..4.71 rows=1 width=12299) (actual time=0.025..0.025 rows=0 loops=1)
        Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Index Scan using ch_2020_rp_fk_idx1 on ch_2020 ch_4  (cost=0.69..6030.67 rows=1510 width=10259) (actual time=0.029..0.029 rows=0 loops=1)
        Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Bitmap Heap Scan on ch_2021 ch_5  (cost=55.08..3392.36 rows=841 width=9566) (actual time=0.018..0.019 rows=0 loops=1)
        Recheck Cond: (rp_fk = 'abc123'::bpchar)
        ->  Bitmap Index Scan on ch_2021_rp_fk_idx1  (cost=0.00..54.87 rows=841 width=0) (actual time=0.016..0.016 rows=0 loops=1)
              Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Index Scan using ch_2022_rp_fk_idx on ch_2022 ch_6  (cost=0.12..8.14 rows=1 width=12241) (actual time=0.013..0.013 rows=0 loops=1)
        Index Cond: (rp_fk = 'abc123'::bpchar)
  ->  Seq Scan on ch_def ch_7  (cost=0.00..1.05 rows=1 width=12167) (actual time=0.009..0.009 rows=0 loops=1)
        Filter: (rp_fk = 'abc123'::bpchar)
        Rows Removed by Filter: 4
Planning Time: 24.637 ms
Execution Time: 0.538 ms

但是,当将 ch 表与 p 表连接时,它会从其中获取 rp_fk,它会对 ch_2018 和 ch_2019 分区进行顺序扫描。这是它花费大部分时间的地方,而 2020 和 2021 分区是使用索引扫描的。关于为什么在这两个分区上使用 seq 扫描的任何见解?所有分区都具有相同的索引并具有最新的真空分析。 random_page_cost 设置为 1。

explain analyze select * FROM oc.ch ch JOIN op.p p ON ch.rp_fk = p.p_pk WHERE ch.del_flg = '0'::bpchar and hf_p_num_cd ='112642817-002'; 

Nested Loop  (cost=0.42..13134696.50 rows=96 width=12593) (actual time=193878.564..193878.569 rows=0 loops=1)
  ->  Index Scan using ix_p_hf_p_num_cd on p p  (cost=0.42..8.44 rows=1 width=1420) (actual time=0.025..0.028 rows=1 loops=1)
        Index Cond: ((hf_p_num_cd)::text = '112642817-002'::text)
  ->  Append  (cost=0.00..12666318.27 rows=46836978 width=11167) (actual time=193878.532..193878.535 rows=0 loops=1)
        ->  Seq Scan on ch_2016 ch  (cost=0.00..11.57 rows=13 width=11097) (actual time=0.072..0.072 rows=0 loops=1)
              Filter: ((del_flg = '0'::bpchar) AND (p.p_pk = rp_fk))
              Rows Removed by Filter: 38
        ->  Index Scan using ch_2017_rp_fk_idx1 on ch_2017 ch_1  (cost=0.14..20.94 rows=40 width=10477) (actual time=0.016..0.016 rows=0 loops=1)
              Index Cond: (rp_fk = p.p_pk)
              Filter: (del_flg = '0'::bpchar)
        ->  Seq Scan on ch_2018 ch_2  (cost=0.00..4005273.43 rows=15109962 width=12295) (actual time=25051.825..25051.825 rows=0 loops=1)
              Filter: ((del_flg = '0'::bpchar) AND (p.p_pk = rp_fk))
              Rows Removed by Filter: 15111645
        ->  Seq Scan on ch_2019 ch_3  (cost=0.00..8406638.77 rows=31721918 width=12299) (actual time=168826.481..168826.481 rows=0 loops=1)
              Filter: ((del_flg = '0'::bpchar) AND (p.p_pk = rp_fk))
              Rows Removed by Filter: 31722679
        ->  Index Scan using ch_2020_rp_fk_idx1 on ch_2020 ch_4  (cost=0.69..14893.73 rows=3729 width=10259) (actual time=0.057..0.057 rows=0 loops=1)
              Index Cond: (rp_fk = p.p_pk)
              Filter: (del_flg = '0'::bpchar)
        ->  Bitmap Heap Scan on ch_2021 ch_5  (cost=82.74..5285.74 rows=1314 width=9566) (actual time=0.033..0.033 rows=0 loops=1)
              Recheck Cond: (rp_fk = p.p_pk)
              Filter: (del_flg = '0'::bpchar)
              ->  Bitmap Index Scan on ch_2021_rp_fk_idx1  (cost=0.00..82.42 rows=1314 width=0) (actual time=0.022..0.022 rows=0 loops=1)
                    Index Cond: (rp_fk = p.p_pk)
        ->  Index Scan using ch_2022_rp_fk_idx on ch_2022 ch_6  (cost=0.12..8.14 rows=1 width=12241) (actual time=0.014..0.014 rows=0 loops=1)
              Filter: ((del_flg = '0'::bpchar) AND (p.p_pk = rp_fk))
        ->  Seq Scan on ch_def ch_7  (cost=0.00..1.06 rows=1 width=12167) (actual time=0.017..0.017 rows=0 loops=1)
              Filter: ((del_flg = '0'::bpchar) AND (p.p_pk = rp_fk))
              Rows Removed by Filter: 4
Planning Time: 4.183 ms
Execution Time: 193878.918 ms

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    似乎'abc123'rp_fk 的一个非常罕见的值,因此PostgreSQL 计划进行索引扫描。

    但似乎有些值更频繁。在第二个查询中,优化器不知道rp_fkhf_p_num_cd = '112642817-002' 的值是多少,所以它采用了一些平均估计值,结果证明对于许多分区来说要高得多。因此是顺序扫描。

    我会将查询分成两部分,并使用在第一个查询中找到的常量查询分区表。然后优化器知道的更多,并且会更好地计划。

    如果您确定索引扫描将始终获胜,则可以强制规划者:

    BEGIN;
    SET LOCAL enable_seqscan = off;
    SET LOCAL enable_bitmapscan = off;
    SELECT ...
    COMMIT;
    

    【讨论】:

    • 谢谢,确实是这样 - 一个值在 99% 的时间里出现。
    猜你喜欢
    • 1970-01-01
    • 2010-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多